home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / emerald / emrldsys.lha / Kernel / Em / msgCode.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-08-17  |  71.9 KB  |  2,167 lines

  1.  
  2. /*
  3.  * @(#)msgCode.c    1.6  2/23/90
  4.  */
  5.  
  6. /* COPYRIGHT  NOTICE:
  7.  * Copyright 1986 Eric Jul.  May not be used for any
  8.  * purpose without written permission from the author.
  9.  * Certain portions have been derived from Eden code.
  10.  *
  11.  * These routines implement the message level of the
  12.  * Message Module.  It creates, manipulates, and destroys messages.
  13.  * It provides a partially flow controlled data link
  14.  * point-to-point transmission to other Eden hosts.
  15.  * A reliable pipeline protocol is used.
  16.  * Retransmission and piggybacked acknowledgements.
  17.  *
  18.  * Timeout values need tuning
  19.  * Message timeout is primitive as to improve performance.
  20.  * The variable HOTS is global within this module.  It references
  21.  * the current logical node being talked to - if any.
  22.  * The primitive hack to handle NOHOTSENTRY situations should be fixed.
  23.  */
  24.  
  25.  
  26. extern void ErrMsg();
  27. #ifdef xkernel
  28. #include <sys/types.h>
  29. #include "userupi.h"
  30. #include "userprocess.h"
  31. #include "ip.h"
  32. #include "udp.h"
  33. #include "debug.h"
  34.  
  35. static IPaddr myipaddr;
  36. #else
  37. #include <errno.h>
  38. #include <sys/types.h>
  39. #include <sys/file.h>
  40. #include <sys/ioctl.h>
  41. #include <netdb.h>
  42. extern errno;
  43. #endif
  44.  
  45. extern char *inet_ntoa();
  46. #undef integer
  47.  
  48. #include "Kernel/h/system.h"
  49. #include "Kernel/h/assert.h"
  50. #include "Kernel/h/macros.h"
  51. #include "Kernel/h/mmTypes.h"
  52. #include "Kernel/h/mmCodes.h"
  53. #include "Kernel/h/unixCodes.h"
  54. #include "Kernel/h/mmBufTypes.h"
  55. #include "Kernel/h/mmFifoTypes.h"
  56. #include "Kernel/h/mmMsgDefs.h"
  57. #include "Kernel/h/mmMsgTypes.h"
  58. #include "Kernel/h/mmEthrTypes.h"
  59. #include "Kernel/h/hotsTypes.h"
  60. #include "Kernel/h/kEvents.h"
  61. #include "Kernel/h/timerTypes.h"
  62. #include "Kernel/h/kmdTypes.h"
  63. #include "Kernel/h/sigio.h"
  64.  
  65. /*++BRDADDR++*/
  66. #include <net/if.h>
  67. /*--BRDADDR--*/
  68.  
  69.  
  70. #define endcase break
  71.  
  72. extern int  DisplayEdenMsg(),
  73.         GetEdenMsg(),
  74.         PutEdenMsg();
  75.  
  76. extern void     KMDInterrupt();
  77. extern void     QueueTask();
  78. extern void     SISetSockHandler();
  79. extern time_t   nodeIncarnationId;
  80.  
  81. /* Forward */
  82. HResult  MMReceiveEtherHandler();
  83. void     MMInitHOTSEntry(), MMStats(), EtherStats();
  84. static KKStatus SendFrame();
  85.  
  86. /************************************************************/
  87. /*                   Static Global Variables                */
  88. /************************************************************/
  89.  
  90. NodeNum   MMLocalLNN  = 0;
  91. EdenPort  MMNetPort   = NULLEDENPORT;
  92. MessageId MMNextMsgId = FIRSTMSGID;
  93.  
  94. Boolean HasNetPort = False;                 /* Set by MMInitMsgModule. */
  95.  
  96. #ifdef BSD
  97. int             MMEtherFile = -1;
  98. #else
  99. #ifdef xkernel
  100. SESSN           MMEtherSessn = ERR_SESSN;
  101. PROTL           MMEtherProtl = ERR_PROTL;
  102.  
  103. #define EMXSEND(ses,par,pak,siz,bytes) {\
  104.   (ses) = xopen(MMEtherProtl,UDP,(par));\
  105.   (bytes) = xpush((ses), (pak), (siz));\
  106. }
  107.  
  108.  
  109. #endif
  110. #endif
  111. EtherNetAddress MMLocalEtherNet = {0};  /* All zeros, believe it or not */
  112. EtherNetAddress MMBroadcastAddr;
  113. unsigned short  MMBroadcastPort;
  114. char        vMMEtherDevName[100] = "";
  115.  
  116. #ifdef xkernel
  117. /******************
  118.   xkernel handlers
  119. ******************/
  120. /*ARGSUSED*/
  121. MMdemux_handler(s, msg, len)
  122. SESSN s;
  123. register char *msg;
  124. int len;
  125. {
  126.   MessagePtr newmsg;
  127.   KKStatus status;
  128.  
  129.   xkhandlerstart();
  130.   DebugMsg(4, "MMdemux_handler, len = %d\n", len);
  131.   /* trivially does what SIGIO handler used to do (less socket reads) */
  132.   status = MMAllocateMsg( MAXMESSAGESIZE, &newmsg);
  133.   if(mSUCCESS(status)) {
  134.     bcopy(msg,(char *)newmsg,len);
  135.     HoldSigs();
  136.     QueueTask( (HandlerPtr)MMReceiveEtherHandler, (char *)newmsg);
  137.     ReleaseSigs();
  138.   } else ErrMsg(">> MMdemux_handler got no buffer 0x%02x\n", status);
  139.   xkhandlerend();
  140. }
  141. MMopendone_handler()
  142. {
  143.   xkhandlerstart();
  144.   DebugMsg(3, "MMopendone_handler\n");
  145.   xkhandlerend();
  146. }
  147. MMclosedone_handler()
  148. {
  149.   xkhandlerstart();
  150.   xkhandlerend();
  151. }
  152. #endif
  153.  
  154. /* Protocol administration definitions.
  155.  * Most of the following are local constants, but have been defined as
  156.  * global variables, so that tuning of the protocol may be done by
  157.  * adjusting these variable, e.g., at boot time, or even dynamically.
  158.  * The global variables have been named something with "MM" and have
  159.  * prefixed with "v".  Variables prefixed by "c" may be inspected only.
  160.  * Notes:
  161.  *  The vMM* variables may be reset by changing their value via the KMD
  162.  *  'changevar' procedure, or by setting their new values in the
  163.  *  local 'kernelrc' file, or the '/usr/em/emrc' file.
  164.  * Restrictions:
  165.  *  vMMSendWindow > 0              -- Else protocol Invalid
  166.  *  2*vMMSendWindow + 1 < SEQRANGE -- Else protocol Invalid
  167.  *  vMMACKTimeout < vMMMsgTimeout  -- Else too many retransmits & NAKs.
  168.  *  vMMACKTimeout > 1              -- Since one tick may expire immediately.
  169.  *  vMMMsgTimeout > 1
  170.  * Preferences:
  171.  *  vMMACKTimeout < vMMMsgTimeout - 1
  172.  *                                 -- Else risk too close.
  173.  *  vMMForceAck > 1                -- Else ACK for every msg.
  174.  *  vMMForceAck <= vMMSendWindow+1 -- Else No Forced ACK ever. (Can be
  175.  *                                 -- used to turn it off.)
  176.  *  vMMForceAck <  vMMSendWindow   -- To prevent a high-volume sender
  177.  *                                 -- from blocking due to window full.
  178.  */
  179.  
  180. #define MAXSEQNO        255             /* Must fit into a byte. */
  181. #define SEQRANGE        256             /* MAXSEQNO + 1  */
  182.  
  183. #define MAXSWSIZE        4              /* Max size of Send window. */
  184. int     vMMSendWindow   = MAXSWSIZE;    /* must be < (MAXSEQNO - 1)/2 */
  185. #define FORCEACK         3              /* # of unACKed msg to force ACK */
  186. int     vMMForceAck     = FORCEACK;
  187. #define TICKSIZE        1000000         /* microseconds per tick */
  188. int     vMMTickSize     = TICKSIZE;
  189. #define MSGTIMEOUTCOUNT 6               /* Tick count for msg timeout */
  190. int     vMMMsgTimeout   = MSGTIMEOUTCOUNT;
  191. #define ACKTIMEOUTCOUNT 2               /* Tick count for ACK timeout */
  192. int     vMMACKTimeout   = ACKTIMEOUTCOUNT;
  193. #define RETRANSCOUNT    100             /* For declaring nodes dead*/
  194. int     vMMBigRetransCount
  195.             = RETRANSCOUNT;
  196.  
  197. /************ Statistical variables ************/
  198. /*  For statistical use only                   */
  199. long    cMMOutOfOrderCount      = 0;
  200. long    cMMRetransCount         = 0;
  201. long    cMMNAKsSentCount        = 0;
  202. long    cMMNAKsRecvCount        = 0;
  203. long    cMMMsgDroppedCount      = 0;
  204. long    cMMACKsSentCount        = 0;
  205. long    cMMACKsRecvCount        = 0;
  206. long    cMMMsgDeliveredCount    = 0;
  207. long    cMMMsgAcceptedCount     = 0;
  208. long    cMMMsgSentSynchRawCount = 0;
  209. long    cMMBroadcastHOSTCount   = 0;
  210. long    cMMMulticastCount       = 0;
  211. long    cMMBcastDefaultCount    = 0;
  212. long    cMMFirstFCMsgCount      = 0;
  213. long    cMMEtherPacketSentCount = 0;
  214. long    cMMAccumPacketSize      = 0;
  215. long    cMMNormalInterruptCount = 0;
  216. long    cMMEmergencyIntCount    = 0;
  217. long    cMMEthernetIntCount     = 0;
  218. long    cMMMsgAllocCount        = 0;
  219. long    cMMMsgDeAllocCount      = 0;
  220. long    cMMMsgSentSynchCount    = 0;
  221. long    cMMMsgSentRawCount      = 0;
  222. long    cMMMsgSentCount         = 0;
  223. long    cMMAccumMsgSize         = 0; /* Divide by cMMMsgSentCount */
  224.  
  225. /************ End of Statistical Variables ************/
  226.  
  227.  
  228. /************************************************************/
  229. /*                   Static Local Variables                 */
  230. /************************************************************/
  231.  
  232. #define NxtSeq(X)   (X == MAXSEQNO ? 0 : X + 1)
  233. #define PrvSeq(X)   (X == 0 ? MAXSEQNO : X - 1)
  234. #define IncSeq(X)   if (X++ == MAXSEQNO) X=0
  235.  
  236.  
  237. /* Local variables */
  238.  
  239. static HOTSRecord  *HOTS;
  240. static HOTSRecord  defaultHOTS; /* Used when only a single HOTS entry is
  241.                  * needed, rather than a full HOTS table
  242.                  * (saves allocating a full table and
  243.                  * linking in unneeded HOTS table
  244.                  * manipulation routines)
  245.                  */
  246.  
  247. static Boolean     TimerActive;
  248. static HOTSRecord  THead;
  249. static EnetPacket  SNpacket;
  250.  
  251. #define TextSize 100
  252. char    ErrorText[TextSize];
  253.  
  254.  
  255. /************************************************************/
  256. /*                   Local Subroutines                      */
  257. /************************************************************/
  258.  
  259.  
  260.  
  261. #define between(a,b,c) (a<=b && b<c || c<a && a<=b || b<c && c<a)
  262.  
  263. #define CheckTimer                                                          \
  264.     if (! HOTS->Timed) {                                                \
  265.         /* Start timing of this logical node: Insert in timer list.*/   \
  266.         MXTraceMsg(5, "Timeout queue insert lnn = %d\n", HOTS->LNN);    \
  267.         HOTS->TNext             = THead.TNext;                          \
  268.         HOTS->TPrev             = &THead;                               \
  269.         (THead.TNext)->TPrev    = HOTS;                                 \
  270.         THead.TNext             = HOTS;                                 \
  271.         HOTS->Timed             = TRUE;                                 \
  272.         /* Start the timeout handler if is not already active. */       \
  273.         if (!TimerActive) {                                             \
  274.         MXTraceMsg(5, "Start timer Q on LNN = %d\n", MMLocalLNN);   \
  275.         TimerActive = TRUE;                                         \
  276.         (void) MMSetMicroTimer((int) (vMMTickSize/1000000),           \
  277.             (int) (vMMTickSize%1000000), (HandlerPtr) TimeoutHandler, \
  278.             NULL, (TimerId *) NULL);                                \
  279.         }                                                               \
  280.     };
  281.  
  282.  
  283.  
  284. /*************************************************************************
  285.  *    Upcall Routines. These routines allow higher level routines to     *
  286.  *    associate handlers with specific events that arise in the low      *
  287.  *    level message module routines.  This has 2 purposes: first,        *
  288.  *    it insulates the HOTS table representation from the message        *
  289.  *    module; second, it allows the message module to be used in         *
  290.  *    programs that don't access the HOTS table (such the message        *
  291.  *    module test program).  Included in this set of routines are the    *
  292.  *    default routines (which simply announce when they are called)      *
  293.  *    and a routine to allow reassociation of routines with events.      *
  294.  *************************************************************************/
  295.  
  296. static KKStatus MMDefaultHOTSSearchPtrHandler(fQueryLNN, fEntryPtr)
  297. NodeNum fQueryLNN;
  298. HOTSRecord **fEntryPtr;
  299. {
  300.   MXTraceMsg(5, "MMDefaultHOTSSearchPtrHandler: fQueryLNN = %d\n", fQueryLNN);
  301.   if (defaultHOTS.LNN == (NodeNum) 0){
  302.     /* defaultHOTS hasn't been setup. Note: this check assumes that
  303.        LNN 0 is never used as a real Kernel or POD */
  304.     return(MMSF_DefaultHOTSNotInitialized);
  305.   } else {
  306.     (*fEntryPtr) = &defaultHOTS;  /* Return the single default HOTS record 
  307.                      from the message module */
  308.     MXTraceMsg(6, "MMDefaultHOTSSearchPtrHandler: &defaultHOTS = 0x%05x\n", 
  309.            &defaultHOTS);
  310.     MXTraceMsg(6, "MMDefaultHOTSSearchPtrHandler: defaultHOTS.LNN = %d;\n", 
  311.            defaultHOTS.LNN);
  312.     MXTraceMsg(6, "MMDefaultHOTSSearchPtrHandler: EthAdr in defaultHOTS.EtherAddr = %s.\n", inet_ntoa(defaultHOTS.EtherAddr.sin_addr));
  313.     MXTraceMsg(6, "MMDefaultHOTSSearchPtrHandler: defaultHOTS.EtherAddr.sin_port = %d\n",
  314.            ntohs(defaultHOTS.EtherAddr.sin_port));
  315.     MXTraceMsg(6, "MMDefaultHOTSSearchPtrHandler: defaultHOTS.NodeStat = %d\n",
  316.            defaultHOTS.NodeStat);
  317.     return(MMSS_Success);
  318.   }
  319. }
  320.  
  321. void MMSetupDefaultHOTSEntry(fHOTSEntry)
  322. HOTSRecord fHOTSEntry;
  323. {
  324.   MXTraceMsg(4, "MMSetupDefaultHOTSEntry: fHOTSEntry.LNN = %d\n", 
  325.          fHOTSEntry.LNN);
  326.   MXTraceMsg(4,
  327.          "MMSetupDefaultHOTSEntry: fHOTSEntry.EtherAddr = %s, port = %d\n",
  328.          inet_ntoa(fHOTSEntry.EtherAddr.sin_addr),
  329.          ntohs(fHOTSEntry.EtherAddr.sin_port));
  330.   MXTraceMsg(4, "MMSetupDefaultHOTSEntry: fHOTSEntry.NodeStat = %d\n", 
  331.          fHOTSEntry.NodeStat);
  332.   defaultHOTS = fHOTSEntry;  /* Copy the passed HOTS entry into the MM 
  333.                 global variable defaultHOTS */
  334.   /* Now DO NOT forget to initialize protocol stuff */
  335.   MMInitHOTSEntry(&defaultHOTS);
  336. }
  337.  
  338. /*ARGSUSED*/
  339. static KKStatus MMDefaultBigRetransCountHandler(fHOTSRec)
  340. HOTSRecord *fHOTSRec;
  341. {
  342.   MXTraceMsg(1, "MMDefaultBigRetransCountHandler was called\n");
  343.   return(MMSS_Success);
  344. }
  345.  
  346. /*ARGSUSED*/
  347. static KKStatus MMDefaultEdenPortDeathHandler(fPort)
  348. EdenPort fPort;
  349. {
  350.   MXTraceMsg(4, "MMDefaultEdenPortDeathHandler: Port = %d\n", fPort);
  351.   return(MMSS_Success);
  352. }
  353.  
  354. /*ARGSUSED*/
  355. static KKStatus MMDefaultNoHOTSEntryHandler(fMsg)
  356. MessagePtr fMsg;
  357. {
  358.   /* The default action for a missing HOTS entry is to do nothing */
  359.   MXTraceMsg(4, "MMDefaultNoHOTSEntryHandler: LNN = %d\n", 
  360.          fMsg->MsgHdr.MsgSrc);
  361.   return(MMSF_NoHOTSEntry);
  362. }
  363.  
  364. /*ARGSUSED*/
  365. static KKStatus MMDefaultSendWindowFullHandler(fHOTSRec)
  366. HOTSRecord *fHOTSRec;
  367. {
  368.    /* The default action for send window full is to do nothing */
  369.    MXTraceMsg(5, "MMDefaultSendWindowFullHandler was called\n");
  370.    return(MMSS_Success);
  371. }
  372.  
  373. /*ARGSUSED*/
  374. static KKStatus MMDefaultSendWindowNotFullHandler(fHOTSRec)
  375. HOTSRecord *fHOTSRec;
  376. {
  377.    /* The default action for send window not full is to do nothing */
  378.    MXTraceMsg(5, "MMDefaultSendWindowNotFullHandler was called\n");
  379.    return(MMSS_Success);
  380. }
  381.  
  382. /*ARGSUSED*/
  383. static KKStatus MMDefaultFirstFCMsgReceivedHandler(fHOTSRec, fMsg)
  384. HOTSRecord *fHOTSRec;
  385. MessagePtr fMsg;
  386. {
  387.    /* The default action for first flow controlled msg received from the LNN
  388.       associated with fHOTSRec is to do nothing */
  389.    MXTraceMsg(4, "MMDefaultFirstFCMsgReceivedHandler was called, LNN %d\n",
  390.     fHOTSRec->LNN);
  391.    return(MMSS_Success);
  392. }
  393.  
  394. /*ARGSUSED*/
  395. static KKStatus MMDefaultCheckMsgHandler(fMsg, fEntryPtr)
  396. MessagePtr fMsg;
  397. HOTSRecord **fEntryPtr;
  398. {
  399.     MXTraceMsg(6, "MMDefaultCheckMsgHandler called.\n");
  400.     return(MMDefaultHOTSSearchPtrHandler(0, fEntryPtr));
  401. }
  402. typedef KKStatus (*MMUpcallHandlerType) ();
  403.  
  404. MMUpcallHandlerType MMUpcallHandler[NUMUPCALLEVENTS] = {
  405.    MMDefaultHOTSSearchPtrHandler,
  406.    MMDefaultBigRetransCountHandler,
  407.    MMDefaultEdenPortDeathHandler,
  408.    MMDefaultNoHOTSEntryHandler,
  409.    MMDefaultSendWindowFullHandler,
  410.    MMDefaultSendWindowNotFullHandler,
  411.    MMDefaultFirstFCMsgReceivedHandler,
  412.    MMDefaultCheckMsgHandler
  413. };
  414.  
  415. KKStatus MMDefineUpcallHandler(fRoutine, fHandlerNumber)
  416. HandlerPtr fRoutine;
  417. int fHandlerNumber;
  418. {
  419.    MXTraceMsg(4, "MMDefineUpcallHandler: fHandlerNumber = %d\n",
  420.           fHandlerNumber);
  421.    if (fHandlerNumber < 0  ||  fHandlerNumber >= NUMUPCALLEVENTS)
  422.       return(MMSF_BadEventID);
  423.    MMUpcallHandler[fHandlerNumber] = (MMUpcallHandlerType) fRoutine;
  424.    return(MMSS_Success);
  425. }
  426.  
  427. #ifdef DEFUNCT
  428. /*                                      */
  429. /* Search the HOTS table for the LNN    */
  430. /*                                      */
  431.  
  432. static KKStatus FindLNN( fLNN,
  433.              fDestAddr
  434.                )
  435.        NodeNum     fLNN;
  436.   register DeviceAddr *fDestAddr;
  437. {
  438.   HOTSRecord   *info;
  439.   KKStatus     status;
  440.  
  441.   MXTraceMsg(5, "FindLNN( %d, %d )\n", fLNN, fDestAddr);
  442.  
  443.   /* Call higher level routine to search HOTS table */
  444.   status = MMUpcallHandler[HOTSSEARCHPTR]( fLNN, &info ); 
  445.  
  446.   if ( ! mSUCCESS( status ) )
  447.     return MMSF_BadNode;
  448.   if ( info->NodeStat == Dead )
  449.     return MMSF_NodeDown;
  450.   status = MMSS_Success;
  451.   fDestAddr->DevicePort = NULLEDENPORT;
  452.   mEtherCopy( &(info->EtherAddr), &(fDestAddr->DeviceEnet) );
  453.   
  454.   MXTraceMsg(5, "end FindLNN( %d, %d )\n", (int)fDestAddr->DevicePort,
  455.            (int) MachineAddress(fDestAddr->DeviceEnet));
  456.  
  457.   return status;
  458. }
  459.  
  460. #endif DEFUNCT
  461.  
  462. /**********************************************************************/
  463. /*      MM snapshots defined for KMD use.                             */
  464. /*      EtherStats(LNN)         The Ethernet stats for communication  */
  465. /*                              with the specified LNN                */
  466. /*                              If LNN=0 then all MM EtherStats.      */
  467. /*      MMStats                 Dumps all MMStats                     */
  468. /**********************************************************************/
  469.  
  470. void EtherStats(fLNN)
  471. int fLNN;
  472. {
  473.     HOTSRecord  *HOTSPtr;
  474.     KKStatus status;
  475.     
  476.     if (fLNN == 0) {        /* Print Etherstats in general. */
  477.     KMDPrint("EtherNet statistics\n");
  478.     KMDPrint("ReTran NAKSen NAKRcv MsgDrp ACKSen ACKRcv MsgDlv MsgAcp OutOrd\n%5d %6d %6d %6d %6d %6d %6d %6d %6d\n",
  479.         cMMRetransCount,
  480.         cMMNAKsSentCount, cMMNAKsRecvCount, cMMMsgDroppedCount,
  481.         cMMACKsSentCount, cMMACKsRecvCount, cMMMsgDeliveredCount,
  482.         cMMMsgAcceptedCount, cMMOutOfOrderCount);
  483.     return;
  484.     }
  485.  
  486.     /* Call higher level routine to search HOTS table */
  487.     status = MMUpcallHandler[HOTSSEARCHPTR](fLNN, &HOTSPtr);  
  488.  
  489.     if (! mSUCCESS(status) ) {
  490.     KMDPrint("LNN not found in HOTS table - status 0x%02x\n", status);
  491.     return;
  492.     };
  493.     
  494.     KMDPrint("EtherNet Message Module statistics for LNN = %d\n", fLNN);
  495.     KMDPrint("ReTran NAKSen NAKRcv MsgDrp ACKSen ACKRcv MsgDlv MsgAcp\n%5d %6d %6d %6d %6d %6d %6d %6d\n",
  496.     HOTSPtr->RetransCount, HOTSPtr->NAKsSent, HOTSPtr->NAKsRecv,
  497.     HOTSPtr->MsgDropped, HOTSPtr->ACKsSent, HOTSPtr->ACKsRecv,
  498.     HOTSPtr->MsgDelivered, HOTSPtr->MsgAccepted);
  499. }
  500.  
  501.  
  502. void MMStats()
  503. {
  504.     KMDPrint("Message Module statistics\n");
  505.     EtherStats(0);
  506.     KMDPrint("SynMsg SynRaw BcstPO Mulcst BcstDf FstFCM\n%5d %6d %6d %6d %6d %6d\n",
  507.         cMMMsgSentSynchCount, cMMMsgSentSynchRawCount,
  508.         cMMBroadcastHOSTCount, cMMMulticastCount,
  509.         cMMBcastDefaultCount, cMMFirstFCMsgCount);
  510.     KMDPrint("MsgAlloc MsgDeAll NormlInt EmergInt EtherInt\n%6d %8d %8d %8d %8d\n",
  511.         cMMMsgAllocCount,
  512.         cMMMsgDeAllocCount, cMMNormalInterruptCount,
  513.         cMMEmergencyIntCount, cMMEthernetIntCount);
  514.     KMDPrint("Total msg sent: %d   Average size %d bytes.\n",
  515.         cMMMsgSentCount, cMMAccumMsgSize
  516.         / (cMMMsgSentCount ? cMMMsgSentCount : 1));
  517.     return;
  518. }
  519.  
  520. /***********************************************************************/
  521. /*          Flow control protocol part.                                */
  522. /*  Contains the routines which have been added to the message module  */
  523. /*  to support the flow control protocol for normal messages.          */
  524. /*  IMPORTANT NOTE:  Most of these routines assume that the current    */
  525. /*  LNNs HOTS entry may be accessed via the pointer HOTS.              */
  526. /*                                                                     */
  527. /*  See "Eden Reliable message passing in Eden. A Sliding Window       */
  528. /*  Protocol for Eden", Eric Jul, Eden Project, 84-02-19               */
  529. /***********************************************************************/
  530.  
  531. /*Forward*/
  532. void SendSubNetPacket();
  533.  
  534. void AckTimeout()
  535. {
  536.     /* Ack Timer has expired; send a separate ack. */
  537.     MXTraceMsg(3, "AckTimeout LNN %d, sending ACK for msg #%d\n",
  538.     HOTS->LNN, HOTS->MsgExpected);
  539.     HOTS->ACKsSent++;  cMMACKsSentCount++;
  540.     SendSubNetPacket(SNACK, (MessagePtr) NULL);
  541. }
  542.  
  543.  
  544. /***********************************************************************/
  545. void MsgTimeout()
  546. {
  547.     FramePtr            FP;
  548.     
  549.     /* Msg Timer has expired; Retransmit a packet. */
  550.     MXTraceMsg(2, "MsgTimeout for LNN %d\n", HOTS->LNN);
  551.     /* Assume (HOTS->SentPtr != NULL) is equivalent to (HOTS->SentPtr) */
  552.     if ( HOTS->SentPtr ) {
  553.     QueueRmv(HOTS->SentPtr, FP, Next);
  554.     MXTraceMsg(2, "Retransmitting msg #%d for the %dth time\n",
  555.         FP->packet.EnetData.MsgHdr.MsgSeq, (FP->RetransCount) + 1);
  556.     HOTS->RetransCount++; cMMRetransCount++;
  557.     QueueIns(HOTS->SentPtr, FP, Next);
  558.     (void) SendFrame(FP);
  559.  
  560.     /* Now if the retransmit count is big inform upper levels
  561.        by doing an upcall.
  562.     */
  563.     if (FP->RetransCount++ > vMMBigRetransCount) {
  564.         MXTraceMsg(1, "**> Big ReTransCount %d for LNN %d\n",
  565.         FP->RetransCount, HOTS->LNN);
  566.         (void) MMUpcallHandler[BIGRETRANSCOUNT](HOTS); /* Call higher level
  567.                                   handler routine */
  568.     };
  569.     };
  570. }
  571.  
  572.  
  573. /***********************************************************************/
  574. HResult TimeoutHandler()
  575. {
  576.   /* Check for timeouts. */
  577.   TimerId dummy;
  578.     
  579.   MXTraceMsg(4, "TimeoutHandler checking nodes:\n");
  580.  
  581.   for (HOTS = THead.TNext; HOTS != &THead; HOTS = HOTS->TNext) {
  582.  
  583.     MXTraceMsg(4, "LNN %4d   AckCount= %4d   MsgCount= %4d\n",
  584.            HOTS->LNN, HOTS->AckTimerCount, HOTS->MsgTimerCount);
  585.  
  586.     /* The following code allows the MsgTimerCount to be left
  587.      * uncancelled:  It will be cancelled at Timeout time instead.
  588.      */
  589.     if ( HOTS->MsgTimerCount > 0 && --HOTS->MsgTimerCount == 0 ) {
  590.       MsgTimeout();
  591.     } else if ( HOTS->SentPtr == NULLFP ) HOTS->MsgTimerCount = 0;
  592.  
  593.     if ( HOTS->AckTimerCount > 0 && --HOTS->AckTimerCount == 0) {
  594.       AckTimeout();
  595.     }
  596.  
  597.     if ( HOTS->MsgTimerCount <= 0 && HOTS->AckTimerCount <= 0 ) {
  598.       /* Dequeue this LNN from timing list. */
  599.       MXTraceMsg(4, "Dropped from timer Q lnn=%d\n", HOTS->LNN);
  600.       HOTS->TNext->TPrev  = HOTS->TPrev;
  601.       HOTS->TPrev->TNext  = HOTS->TNext;
  602.       HOTS->Timed = FALSE;
  603.     }
  604.   }
  605.   
  606.   /* Reset timer if anyone still wants timeouts. */
  607.   if (TimerActive = (THead.TNext != &THead) )
  608.     MMSetMicroTimer((int)(vMMTickSize/1000000), (int)(vMMTickSize%1000000),
  609.             (HandlerPtr)TimeoutHandler, 0, &dummy);
  610. }
  611.  
  612. /***********************************************************************/
  613. /*                  SendFrame                                          */
  614. /*      Send a flow-controlled frame out onto the Ethernet.            */
  615. /*      The destination node's HOTS entry must be accessible thru HOTS. */
  616. /***********************************************************************/
  617. static KKStatus SendFrame(fP)
  618. FramePtr    fP;
  619. {
  620.     int                         size, nbytes;
  621.     KKStatus                    status;
  622.  
  623.     /* Stop ACK timer. */
  624.     MXTraceMsg(4, "ACK Timer stopped.\n");
  625.     HOTS->AckTimerCount = 0;
  626.     HOTS->LatestAck = fP->packet.EnetData.MsgHdr.MsgAck =
  627.                         PrvSeq(HOTS->MsgExpected);
  628.     size = MessageHdrSize + fP->packet.EnetData.MsgHdr.MsgSize;
  629.     MXTraceMsg(3, "SendFrame to LNN %d, msg #%d, Ack %d, SNType %d\n",
  630.         HOTS->LNN,
  631.         fP->packet.EnetData.MsgHdr.MsgSeq,
  632.         fP->packet.EnetData.MsgHdr.MsgAck,
  633.         fP->packet.EnetData.MsgHdr.SNType);
  634.     MXTraceMsg(5,
  635.     "sending to: EtherNetAddr: %s, port: %d\n",
  636.     inet_ntoa(HOTS->EtherAddr.sin_addr),
  637.     ntohs((HOTS->EtherAddr).sin_port));
  638.            
  639.     cMMEtherPacketSentCount++; cMMAccumPacketSize += size;
  640.  
  641. #ifdef BSD
  642.  
  643.     nbytes = sendto( MMEtherFile, &fP->packet, size, 0, &(HOTS->EtherAddr),
  644.              ETHERNETSIZE);
  645.  
  646. #else
  647. #ifdef xkernel
  648.     {
  649.       SESSN s;
  650.       PART  part[3];
  651.       UDPaddr baz,zip;
  652.  
  653.       baz.port = (HOTS->EtherAddr).sin_port;
  654.       *(u_long *)&(baz.host) = (HOTS->EtherAddr).sin_addr.s_addr;
  655.       part[1].address = (char *)&baz;
  656.  
  657.       zip.port = baz.port;
  658.       /* zip.host needs to be assigned here */
  659.       part[0].address = (char *)&zip;
  660.  
  661.       part[2].address = NULL; part[2].length = 0;      /* null terminate */
  662.  
  663.       EMXSEND(s,part,&fP->packet,size,nbytes);
  664.     }
  665. #endif
  666. #endif
  667.  
  668.     MXTraceMsg(5, "SendFrame: after sendto: nbytes,size,errno = %d,%d,%d\n",
  669.            nbytes, size, (nbytes == -1) ? errno : 0);
  670.  
  671.     if ( nbytes == -1 ) {
  672.       status = mSystemError( errno );
  673.     } else if ( nbytes = size ) {
  674.     status = MMSS_Success;
  675.     } else status = mSystemError(errno);
  676.  
  677.     /* Start timeout timer if necessary. */
  678.     if ( ! HOTS->Timed || HOTS->MsgTimerCount <= 0) {
  679.     HOTS->MsgTimerCount = vMMMsgTimeout;
  680.     CheckTimer;
  681.     };
  682.     return status;
  683.  
  684. }
  685.  
  686. /***********************************************************************/
  687. /*                  SendSubNetPacket                                   */
  688. /*      Sends a subnet message which circumvents the flow control      */
  689. /*      and thus delivers the message directly without any further     */
  690. /*      ado except for piggyback ACK.  Assumes that HOTS points to     */
  691. /*      destination.                                                   */
  692. /***********************************************************************/
  693.  
  694. /*ARGSUSED*/
  695. void SendSubNetPacket( fSNType, fmsg)
  696. SubNetType                  fSNType;
  697. MessagePtr                  fmsg;
  698. {
  699.     int                     size, nbytes;
  700.  
  701.     /* Stop ACK timer. */
  702.     MXTraceMsg(4, "ACK Timer stopped.\n");
  703.     HOTS->AckTimerCount = 0;
  704.  
  705.     /* Use the preinitialized packet */
  706.     SNpacket.EnetData.MsgHdr.MsgDest = HOTS->LNN;
  707.     HOTS->LatestAck = SNpacket.EnetData.MsgHdr.MsgAck =
  708.                         PrvSeq(HOTS->MsgExpected);
  709.     SNpacket.EnetData.MsgHdr.SNType = fSNType;
  710.     MXTraceMsg(3, "SendSubNetPacket SNtype %d, destLNN %d, MsgAck %d\n",
  711.     fSNType, SNpacket.EnetData.MsgHdr.MsgDest,
  712.     SNpacket.EnetData.MsgHdr.MsgAck);
  713.     /* Note, for now fmsg MUST be NULL */
  714.     
  715.     size = MessageHdrSize /* + fmsg size */;
  716.     MXTraceMsg(5, "SendSubNetPacket: ethaddr in HOTS->EtherAddr = %s\n",
  717.     inet_ntoa(HOTS->EtherAddr.sin_addr));
  718.     MXTraceMsg(5, "SendSubNetPacket: (HOTS->EtherAddr).sin_port = %d\n",
  719.            ntohs((HOTS->EtherAddr).sin_port));
  720.     cMMEtherPacketSentCount++; cMMAccumPacketSize += size;
  721.  
  722. #ifdef BSD
  723.  
  724.     nbytes = sendto( MMEtherFile, &SNpacket, size, 0, &(HOTS->EtherAddr),
  725.              ETHERNETSIZE);
  726.  
  727. #else
  728. #ifdef xkernel
  729.     {
  730.       SESSN s;
  731.       PART  part[3];
  732.       UDPaddr baz,zip;
  733.  
  734.       baz.port = (HOTS->EtherAddr).sin_port;
  735.       *(u_long *)&(baz.host) = (HOTS->EtherAddr).sin_addr.s_addr;
  736.       part[1].address = (char *)&baz;
  737.  
  738.       zip.port = baz.port; /*?*/
  739.       /* zip.host needs assigning here */
  740.       part[0].address = (char *)&zip;
  741.  
  742.       part[2].address = NULL; part[2].length = 0;
  743.  
  744.       EMXSEND(s,part,&SNpacket,size,nbytes);
  745.     }
  746. #endif
  747. #endif
  748.  
  749.     MXTraceMsg(5, "SendSubNetPacket: after sendto: nbytes, size = %d, %d\n",
  750.            nbytes, size);
  751.     if ( nbytes == -1 ) {
  752.     MXTraceMsg(1, "SendSubNetPacket: error #%d\n", errno);
  753.     }
  754. }
  755.  
  756.  
  757. /************************************************************************/
  758. /*                                                                      */
  759. /*  Assign a message number.                                            */
  760. /*                                                                      */
  761. /************************************************************************/
  762.  
  763. static void AssignMsgId(/* returns */ fMsgId
  764.                )
  765.   MessageId  *fMsgId;
  766. {
  767.  
  768.   *fMsgId = ( MMLocalLNN << 16 ) + MMNextMsgId;
  769.   MMNextMsgId = ( (MMNextMsgId == MAXMSGID) ? FIRSTMSGID : (MMNextMsgId+1) );
  770.  
  771.   MXTraceMsg(6, "Message id %08x allocated\n", *fMsgId);
  772. }
  773.  
  774. /***********************************************************************/
  775.  
  776. static KKStatus InitEthernet(fPort)
  777. int     fPort;              /* Port number for broadcasts */
  778. {
  779.    struct hostent           *hp;
  780.    char myName[MAXHOSTNAMELENGTH];
  781.    KKStatus lStatus;
  782. #ifndef xkernel
  783.    int on = 1;
  784.    struct ifreq ifr;
  785.    int s;
  786.    struct sockaddr_in *sin;
  787. #endif
  788.  
  789.    lStatus = MMSS_Success;
  790.  
  791. #ifdef BSD
  792.    /* Create network UDP socket */
  793.  
  794.    if ((MMEtherFile = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
  795.       return mSystemError(errno);
  796.  
  797.  
  798.    /* Bind a name to the socket so other Unix processes can refer to it.  */
  799.       
  800.    MMBroadcastPort = fPort;
  801.    MMBroadcastAddr.sin_port = MMLocalEtherNet.sin_port = MMBroadcastPort;
  802.    MMBroadcastAddr.sin_family = MMLocalEtherNet.sin_family = AF_INET;
  803.  
  804.    if (bind(MMEtherFile, &MMLocalEtherNet, ETHERNETSIZE) < 0)  {
  805. #ifdef MULTIPLEKERNELS
  806.       if (errno == EADDRINUSE)  {
  807.                 /* If the broadcaqst Port is already in use
  808.                    (e.g. by the Eden Kernel broadcast 
  809.                    process), take any port  */
  810.       MXTraceMsg(1,"%s service port already in use...\n", fServiceName);
  811.       MMLocalEtherNet.sin_port = INADDR_ANY;
  812.       if (bind(MMEtherFile, &MMLocalEtherNet, ETHERNETSIZE) < 0 )
  813.           return mSystemError(errno);
  814.       else  {
  815.           size = ETHERNETSIZE;
  816.           if (getsockname(MMEtherFile, &MMLocalEtherNet, &size) < 0)
  817.           return mSystemError(errno);
  818.           MXTraceMsg(1,"New port number allocated = %d\n",
  819.              ntohs(MMLocalEtherNet.sin_port));
  820.           lStatus = MMSS_ServPortTaken;
  821.       }
  822.       }
  823.       else
  824. #endif MULTIPLEKERNELS
  825.      return mSystemError(errno);
  826.    }
  827. #else
  828. #ifdef xkernel
  829.     {
  830.       PART  part[3];
  831.       UDPaddr foo,bar;
  832.  
  833.       xcontrolprotl(IP,MYADDR,(char *)&myipaddr,IPADLEN);
  834.  
  835.       /* initialize part[0] to me */
  836.       MMBroadcastPort = fPort;
  837.       foo.port = MMLocalEtherNet.sin_port = fPort;
  838.       foo.host = myipaddr;
  839.       part[0].length = sizeof(foo) ;
  840.       part[0].address = (char *)&foo;
  841.  
  842.       /* initialize part[1] to any */
  843.       bar.host = myipaddr;
  844.       xcontrolprotl(IP,MYNET,(char *)&(bar.host),IPADLEN);
  845.       bar.port = foo.port;
  846.       part[1].length = sizeof(bar);
  847.       part[1].address = (char *)&bar;
  848.  
  849.       part[2].address = NULL; part[2].length = 0;      /* null terminate */
  850.  
  851.       if(xopenenable(MMEtherProtl,UDP,part)== -1)
  852.     MXTraceMsg(3, "Can't openenable UDP in msgCode.c!");
  853.     }
  854. #endif
  855. #endif
  856.    
  857.    /* Find out Ethernet address of this machine, and fill in the appropriate
  858.       fields in MMLocalEtherNet */
  859.    
  860.    if (gethostname(myName, MAXHOSTNAMELENGTH - 1) < 0)
  861.       return mSystemError(errno);
  862.    MXTraceMsg(5, "My hostname is %s\n", myName);
  863.    hp = gethostbyname(myName);
  864.    if (hp == NULL)
  865.       return mSystemError(errno);
  866.    COPYADDR(hp->h_addr, &(MMLocalEtherNet.sin_addr.s_addr),
  867.      hp->h_length);
  868.    
  869.  
  870. /*++BRDADDR++*/
  871. #ifndef SIOCGIFBRDADDR
  872.    /* Assume 4.2 non-subnet broadcast, see <netinet/in.h> for IN_* macros */
  873.    COPYADDR(hp->h_addr, &s, hp->h_length);
  874.    s = ntohl(s);
  875.    if ( IN_CLASSA(s) )
  876.     s &= IN_CLASSA_NET;
  877.    else
  878.    if ( IN_CLASSB(s) )
  879.     s &= IN_CLASSB_NET;
  880.    else
  881.     s &= IN_CLASSC_NET;
  882.    MMBroadcastAddr.sin_addr.s_addr = htonl(s);
  883. #else
  884.    /*
  885.     * Get broadcast addr from interface.
  886.     * Good luck! If problems see ifconfig(8) call in
  887.     * /etc/rc* files on your local host.
  888.     */
  889. #ifdef xkernel
  890.    {
  891.      IPaddr bar;
  892.  
  893.      MMBroadcastPort = fPort;
  894.      bar = myipaddr;
  895.      xcontrolprotl(IP,MYNET,(char *)&bar,IPADLEN);
  896.  
  897.      *(IPaddr *)&MMBroadcastAddr.sin_addr.s_addr = bar;
  898.    }
  899. #else
  900. #ifdef BSD
  901.  
  902.    s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
  903.  
  904.    if ( s < 0 ) {
  905.        ErrMsg("InitEthernet: can't create tmp socket.\n");
  906.        perror("InitEthernet");
  907.        exit(1);
  908.    }
  909.    /*
  910.     *     >>>> WARNING <<<<<
  911.     * Need real interface name here. What to do if
  912.     * multiple interfaces?
  913.     * Wally (VAX 11/750, Unix 4.2bsd) uses il0
  914.     * Roskilde (MicroVAX II, Ultrix)  uses qe0
  915.     * Whistler (VAXStar)              uses se0
  916.     * June (8550?)                    uses ni0 (or is it bvpni0?)
  917.     * Megaron (University of Arizona, VAX 8600) uses de0.
  918.     * Diku (DIKU, Copenhagen, Denmark) uses ex0.
  919.     * Thor (DIKU, Copenhagen, Denmark) uses ex0.
  920.     * If the label ETHERDEV is defined then it is used.
  921.     */
  922.     
  923. #ifdef sun
  924. #define ETHERDEV "ie0"
  925. #endif
  926.  
  927. #if defined(vax) && defined(ARIZONA)
  928. #define ETHERDEV "de0"
  929. #endif
  930.  
  931. #ifdef ETHERDEV
  932.    (void) strcpy(ifr.ifr_name, ETHERDEV);
  933. #else  ETHERDEV
  934.    if (!strcmp(myName, "freja.diku.dk")) {
  935.      (void) strcpy(ifr.ifr_name, "ex0");
  936.    } else if (!strcmp(myName, "freja")) {
  937.      (void) strcpy(ifr.ifr_name, "ex0");
  938.    } else if (!strcmp(myName, "thor.diku.dk")) {
  939.      (void) strcpy(ifr.ifr_name, "ex0");
  940.    } else if (!strcmp(myName, "roar.diku.dk")) {
  941.      (void) strcpy(ifr.ifr_name, "se0");
  942.    } else if (!strcmp(myName, "regnar.diku.dk")) {
  943.      (void) strcpy(ifr.ifr_name, "es0");
  944.    } else if (!strcmp(myName, "bjarke.diku.dk")) {
  945.      (void) strcpy(ifr.ifr_name, "se0");
  946.    } else if (!strcmp(myName, "whistler")) {
  947.         (void) strcpy(ifr.ifr_name,"se0");
  948.    } else if (!strcmp(myName, "uw-june")) {
  949.         (void) strcpy(ifr.ifr_name,"ni0");
  950.    } else if (!strcmp(myName, "june")) {
  951.         (void) strcpy(ifr.ifr_name,"ni0");
  952.    } else {
  953. #if defined(vax)
  954.         (void) strcpy(ifr.ifr_name,"qe0");
  955. #endif
  956. #if defined(sun)
  957.         (void) strcpy(ifr.ifr_name,"ec0");
  958. #endif
  959.    }
  960.    
  961. #endif ETHERDEV
  962.  
  963.    if (strcmp(&vMMEtherDevName[0], "") != 0) {
  964.      MXTraceMsg(2, "  Ethernet device: %s\n", ifr.ifr_name);
  965.      strcpy(ifr.ifr_name, &vMMEtherDevName[0]);
  966.    }
  967.    
  968.  
  969.    MXTraceMsg(3, "Ethernet device name: %s\n", ifr.ifr_name);
  970.    
  971.    if ( ioctl(s, (int) SIOCGIFBRDADDR, (caddr_t) &ifr) < 0 ) {
  972.        ErrMsg("InitEthernet: cannot get broadcast address...\n");
  973.        perror("ioctl");
  974.        abort();
  975.    }
  976.    sin = (struct sockaddr_in *) (&ifr.ifr_addr);
  977.    MMBroadcastAddr.sin_addr.s_addr = sin->sin_addr.s_addr;
  978.    (void) close( s );
  979.    
  980. #endif BSD
  981. #endif xkernel
  982. #endif SIOCGIFBRDADDR
  983. /*--BRDADDR--*/
  984.  
  985.    MXTraceMsg(5, "InitEthernet: &MMLocalEtherNet : %d\n", &MMLocalEtherNet);
  986.    MXTraceMsg(3, "InitEthernet: MMLocalEtherNet.sin_port : %d\n",
  987.           ntohs(MMLocalEtherNet.sin_port));
  988.    MXTraceMsg(3, "InitEthernet: EtherNetAddress of MMLocalEtherNet : %s\n",
  989.           inet_ntoa(MMLocalEtherNet.sin_addr));
  990.    MXTraceMsg(3, "    Broadcast address: %s.\n",
  991.           inet_ntoa(MMBroadcastAddr.sin_addr));
  992.  
  993.    /* Set up socket for non-blocking, asynchronous operation */
  994.  
  995. #ifdef BSD
  996.    /* FASYNC says send SIGIO, FNDELAY says do not block */
  997.    if (fcntl(MMEtherFile, F_SETFL, FASYNC | FNDELAY) < 0)
  998.       return mSystemError(errno);
  999.  
  1000.    /* The following tells which process is to get the SIGIO */
  1001.    if (fcntl(MMEtherFile, F_SETOWN, getpid()) < 0)
  1002.       return mSystemError(errno);
  1003. #endif
  1004. #ifdef SO_BROADCAST
  1005.  
  1006. #ifdef BSD
  1007.  
  1008.    if( setsockopt(MMEtherFile, SOL_SOCKET, SO_BROADCAST,
  1009.                         (int) &on, sizeof(on))
  1010.      ) return mSystemError(errno);
  1011. #else
  1012. #ifdef xkernel
  1013.    /* what on earth goes here?! */
  1014. #endif
  1015. #endif
  1016. #endif
  1017.  
  1018.    /* Associate handler with socket I/O completion signal for asynchronous
  1019.       network communication */
  1020.  
  1021. #ifdef BSD
  1022.    SISetSockHandler(MMEtherFile, SIREAD, (SIHandlerPtr) MMEthernetInterrupt);
  1023. #endif
  1024.    return lStatus;
  1025. }
  1026.  
  1027. /*
  1028.  * SendOutMsg
  1029.  *      Send out a msg over the ethernet.
  1030.  *      It is important that the BroadcastMask field be set correctly for
  1031.  *      those msgs going over the ether.
  1032.  */
  1033. #ifdef xkernel
  1034. /*ARGSUSED*/
  1035. #endif
  1036. KKStatus    SendOutMsg(fmsg, faddr )
  1037. MessagePtr  fmsg;    /* Msg to send        */
  1038. DeviceAddr *faddr;   /* Dest, if broadcast */
  1039. {
  1040.     KKStatus                     status;
  1041.     int                          size, nbytes, DestLNN, framelength;
  1042.     register FramePtr            FP;
  1043.     EnetPacket                   packet;
  1044.     MessageHeaderPtr             hdr;
  1045.  
  1046.     cMMMsgSentCount++;  cMMAccumMsgSize += fmsg->MsgHdr.MsgSize;
  1047.  
  1048.     MXTraceMsg(3, "Send MsgId %06x, SNType %d, to LNN %d, MsgType 0x%06x, Subtype 0x%06x\n",
  1049.            fmsg->MsgHdr.MsgId, fmsg->MsgHdr.SNType, fmsg->MsgHdr.MsgDest,
  1050.            fmsg->MsgHdr.MsgType, fmsg->MsgHdr.MsgSubtype);
  1051.  
  1052.     if ( (fmsg->MsgHdr.SNType ==  SNBROADCAST) ) {
  1053.     /* Send out non-flow controlled (broadcast) packet directly */
  1054.     MXTraceMsg(5, "BROADCAST\n");
  1055.     packet.EnetData.MsgHdr = fmsg->MsgHdr;
  1056.     packet.EnetData.MsgHdr.SrcSinPort = MMLocalEtherNet.sin_port;
  1057.     packet.EnetData.MsgHdr.SrcSinAddr = MMLocalEtherNet.sin_addr;
  1058.     packet.EnetData.MsgHdr.SrcIncarnationId = nodeIncarnationId;
  1059.     bcopy((char *) fmsg->MsgData, (char *) packet.EnetData.MsgData,
  1060.              (int)fmsg->MsgHdr.MsgSize);
  1061.     size = MessageHdrSize + fmsg->MsgHdr.MsgSize;
  1062.     cMMEtherPacketSentCount++; cMMAccumPacketSize += size;
  1063.  
  1064. #ifdef BSD
  1065.  
  1066.     nbytes = sendto( MMEtherFile, &packet, size, 0, &(faddr->DeviceEnet),
  1067.              ETHERNETSIZE);
  1068.  
  1069. #else
  1070. #ifdef xkernel
  1071.     {
  1072.       SESSN s;
  1073.       PART  part[3];
  1074.       UDPaddr baz,zip;
  1075.  
  1076.       baz.port = MMBroadcastPort;
  1077.       baz.host = myipaddr;
  1078.       xcontrolprotl(IP,MYNET,(char *)&(baz.host),IPADLEN);
  1079.       part[1].address = (char *)&baz;
  1080.  
  1081.       zip.port = baz.port;
  1082.       /* zip.host gets?? */
  1083.       part[0].address = (char *)&zip;
  1084.  
  1085.       part[2].address = NULL; part[2].length = 0;     /* null terminate */
  1086.  
  1087.       EMXSEND(s,part,&packet,size,nbytes);
  1088.     }
  1089. #endif
  1090. #endif
  1091.  
  1092.     MXTraceMsg(4, "SendOutMsg: bcast, sendto: size,nbytes,errno = %d,%d,%d\n",
  1093.            size, nbytes, (nbytes < 0 ? errno : 0) );
  1094.     if ( nbytes == -1 )
  1095.         status = mSystemError( errno );
  1096.     else if ( nbytes = size ) {
  1097.         status = MMSS_Success;
  1098.     } else status = mSystemError(errno);
  1099.     } else  if ( (fmsg->MsgHdr.SNType !=  SNNORMAL) ) {
  1100.     /* Send out non-flow controlled (raw) packet directly */
  1101.     DestLNN = fmsg->MsgHdr.MsgDest;
  1102.     MXTraceMsg(5, "SendOutMsg RAW msg to LNN %d\n", DestLNN);
  1103.  
  1104.     packet.EnetData.MsgHdr = fmsg->MsgHdr;
  1105.     packet.EnetData.MsgHdr.SrcSinPort = MMLocalEtherNet.sin_port;
  1106.     packet.EnetData.MsgHdr.SrcSinAddr = MMLocalEtherNet.sin_addr;
  1107.     packet.EnetData.MsgHdr.SrcIncarnationId = nodeIncarnationId;
  1108.     bcopy((char *) fmsg->MsgData, (char *) packet.EnetData.MsgData,
  1109.              (int)fmsg->MsgHdr.MsgSize);
  1110.  
  1111.     /* Call higher level routine to search HOTS table */
  1112.     status = MMUpcallHandler[HOTSSEARCHPTR](DestLNN, &HOTS);  
  1113.  
  1114.     /* Note, HOTS is global within this module. */
  1115.     if (! mSUCCESS(status)) return MMSF_BadNode;
  1116.     if (HOTS->NodeStat == Dead) return MMSF_NodeDown;
  1117.  
  1118.     size = MessageHdrSize + fmsg->MsgHdr.MsgSize;
  1119.     cMMEtherPacketSentCount++; cMMAccumPacketSize += size;
  1120.  
  1121. #ifdef BSD
  1122.  
  1123.     nbytes = sendto( MMEtherFile, &packet, size, 0, &(HOTS->EtherAddr),
  1124.              ETHERNETSIZE);
  1125.  
  1126. #else
  1127. #ifdef xkernel
  1128.     {
  1129.       SESSN s;
  1130.       PART  part[3];
  1131.       UDPaddr baz,zip;
  1132.  
  1133.       baz.port = (HOTS->EtherAddr).sin_port;
  1134.       *(u_long *)&(baz.host) = (HOTS->EtherAddr).sin_addr.s_addr;
  1135.       part[1].address = (char *)&baz;
  1136.  
  1137.       zip.port = baz.port;
  1138.       /* zip.host = ?? */
  1139.       part[0].address = (char *)&zip;
  1140.  
  1141.       part[2].address = NULL; part[2].length = 0;
  1142.  
  1143.       EMXSEND(s,part,&packet,size,nbytes);
  1144.     }
  1145. #endif
  1146. #endif
  1147.  
  1148.     MXTraceMsg(4, "SendOutMsg: sendto: size,nbytes,errno = %d,%d,%d\n",
  1149.            size, nbytes, (nbytes < 0 ? errno : 0) );
  1150.     if ( nbytes == -1 )
  1151.         status = mSystemError( errno );
  1152.     else if ( nbytes = size ) {
  1153.         status = MMSS_Success;
  1154.     } else status = mSystemError(errno);
  1155.     } else {
  1156.     /* SNNORMAL message subnet type, flow-controlled */
  1157.     DestLNN = fmsg->MsgHdr.MsgDest;
  1158.     MXTraceMsg(5, "SendOutMsg flow controlled msg to LNN %d\n", DestLNN);
  1159.  
  1160.     /* Call higher level routine to search HOTS table */
  1161.     status = MMUpcallHandler[HOTSSEARCHPTR](DestLNN, &HOTS);  
  1162.  
  1163.     /* Note, HOTS is global within this module. */
  1164.     if (! mSUCCESS(status)) return MMSF_BadNode;
  1165.     if (HOTS->NodeStat == Dead) return MMSF_NodeDown;
  1166.  
  1167.     /* Copy message into a frame. */
  1168.     framelength = sizeof(Frame) + fmsg->MsgHdr.MsgSize - MAXMESSAGESIZE;
  1169.     MXTraceMsg(6, "Allocating frame, size= %d, msgsize= %d\n",
  1170.         framelength, fmsg->MsgHdr.MsgSize);
  1171.  
  1172.     FP = (FramePtr) malloc ((unsigned)framelength);
  1173.     
  1174.     MXTraceMsg(6, "Frame alloc (size = %d) returned %08x\n",
  1175.         framelength, FP);
  1176.     
  1177.     if (FP == NULL) return MMSK_NoMem;
  1178.     FP->RetransCount = 0;
  1179.     hdr = &FP->packet.EnetData.MsgHdr;
  1180.     FP->packet.EnetData.MsgHdr = fmsg->MsgHdr;
  1181.  
  1182.     bcopy((char *) fmsg->MsgData, (char *) FP->packet.EnetData.MsgData,
  1183.              (int)fmsg->MsgHdr.MsgSize);
  1184.     
  1185.     hdr->MsgSeq = HOTS->NextSeqNo;
  1186.     IncSeq(HOTS->NextSeqNo);
  1187.  
  1188.     /* If I have not yet sent a flow-controlled message to this node, use
  1189.        SNType SNFIRSTFCMSG */
  1190.     if (!(HOTS->FirstFCMsgSent)) {
  1191.         MXTraceMsg(2, "SendOutMsg: First flow-controlled message to LNN %d\n",
  1192.                HOTS->LNN);
  1193.         hdr->SNType = SNFIRSTFCMSG;
  1194.         HOTS->FirstFCMsgSent = TRUE;
  1195.     }
  1196.     else
  1197.         hdr->SNType = SNNORMAL;
  1198.  
  1199.     MXTraceMsg(4, "Msg Id %08x  MsgSeq %d  FramePtr %08x\n",
  1200.         hdr->MsgId, hdr->MsgSeq, FP);
  1201.     
  1202.     /* Check to see if we may send it. */
  1203.     if (HOTS->SendWindowSize < vMMSendWindow) {
  1204.         /* Send Frame. */
  1205.         HOTS->SendWindowSize++;
  1206.         IncSeq(HOTS->NextMsgToSend);
  1207.         MXTraceMsg(6, "Sending frame.\n");
  1208.         QueueIns(HOTS->SentPtr, FP, Next);
  1209.         status = SendFrame(FP);
  1210.         MXTraceMsg(6, "SendOutMsg: after SendFrame, status = %d\n",status);
  1211.  
  1212.     } else {
  1213.         /* Queue for later transmission. */
  1214.         if ( MMTrace ) {
  1215.         MXTraceMsg(3,
  1216.           "Send window overflow, msg seq. deferred: %d\n",
  1217.             hdr->MsgSeq);
  1218.         MXTraceMsg(5,
  1219.           "Send window size %d\n", HOTS->SendWindowSize);
  1220.         };
  1221.         QueueIns(HOTS->ToSendPtr, FP, Next);
  1222.         /* upcall for message deferred */
  1223.         MMUpcallHandler[SENDWINDOWFULL](HOTS);
  1224.         status = MMSS_Success;
  1225.     }
  1226.     }
  1227.     return status;
  1228. }
  1229.  
  1230.  
  1231. /************************************************************/
  1232. /*                                                          */
  1233. /*                    MMDefineDimension                     */
  1234. /*                                                          */
  1235. /*  MMDefineDimension is an undocumented procedure which    */
  1236. /* changes the EDENMSG constant used in ethernet packet     */
  1237. /* headers.  It is useful for running test versions of      */
  1238. /* the message module or in applications which do not want  */
  1239. /* to interfere with Eden Kernel communication.             */
  1240. /* Use this call with a dimension number between 0 and 5    */
  1241. /* (0 is default and is used by normal Eden Kernels.)       */
  1242. /* BEFORE calling MMInitMsgModule.  Processes using dimension*/
  1243. /* N will only be able to communicate with other dimension  */
  1244. /* N processes over the ethernet.  IPC messages do not use  */
  1245. /* this dimension number so it has no effect on them. Note  */
  1246. /* that changes could be made to have the same effect on    */
  1247. /* IPC messages if needed.                                  */
  1248. /* Users of this call should be sure they know what they    */
  1249. /* are doing.                                               */
  1250. /************************************************************/
  1251.  
  1252. /* NONFUNCTIONAL since version 3.0 */
  1253. KKStatus MMDefineDimension (fDimension)
  1254.     int fDimension;
  1255. {
  1256.     MXTraceMsg(4, "MMDefineDimension ( %d )\n", fDimension);
  1257.     if (fDimension > 5 || fDimension < 0)
  1258.     return (MMSF_BadConfig);
  1259. /*    EdenMsgK = EDENMSG - fDimension; */
  1260.     return (MMSS_Success);
  1261. }
  1262.  
  1263. /************************************************************/
  1264. /*                                                          */
  1265. /*                    MMMaxMsgBytes                         */
  1266. /*                                                          */
  1267. /*   MMMaxMsgBytes returns the maximum number of user       */
  1268. /*  defined data bytes within a message.  When using this   */
  1269. /*  function for determining invocation message size,       */
  1270. /*  remember this does not include the Escii overhead.      */
  1271. /************************************************************/
  1272.  
  1273. int MMMaxMsgBytes ()
  1274.  {
  1275.     return MAXMESSAGESIZE;
  1276.  }
  1277.  
  1278. /************************************************************/
  1279. /*                                                          */
  1280. /*                    MMInitMsgModule                       */
  1281. /*                                                          */
  1282. /*   MMInitMsgModule initializes all Message Module data    */
  1283. /*  structures and configures itself based on the supplied  */
  1284. /*  parameters.  If fAsynchronous is True,  MMInitMsgModule */
  1285. /*  defines the events required to process asynchronous     */
  1286. /*  interrupts.  If fNetPort is True, communication with    */
  1287. /*  the Ethernet is initialized.   MMInitMsgModule must be  */
  1288. /*  called before accessing any Message Module primitives.  */
  1289. /*  NOTE: Does NOT initialize anything in the protocol      */
  1290. /*  managers part of the HOTS table.                        */
  1291. /*                                                          */
  1292. /*  Possible status codes:                                  */
  1293. /*      MMSS_Success, MMSF_BadConfig, MMSF_Enetx.           */
  1294. /*                                                          */
  1295. /************************************************************/
  1296.  
  1297. KKStatus  MMInitMsgModule( fPort )
  1298. int     fPort;
  1299.  
  1300. {
  1301.   KKStatus      status;
  1302.   HOTSRecord    *info;
  1303.  
  1304. #ifdef xkernel
  1305.   MMEtherProtl = xcreateprotl(MMdemux_handler,
  1306.                    MMopendone_handler,
  1307.                    MMclosedone_handler);
  1308. #endif
  1309.  
  1310.   MXTraceMsg(3,
  1311.     "MMInitMsgModule,  * $Header:   /usr/em/Kernel/MsgOps/RCS/msgCode.v   Revision 5.0  86/05/28 08:27:00  eric Exp$ ( %d )\n",
  1312.     ntohs((unsigned short)fPort));
  1313.  
  1314.   status = MMSS_Success;
  1315.  
  1316.   /* Initialize Message Module globals */
  1317.  
  1318.   MMLocalLNN = GetLNN();
  1319.   MMNextMsgId = FIRSTMSGID;
  1320.   MMNetPort = NULLEDENPORT;
  1321.   MMInitTimer();
  1322.   (void) MMDefineMsgHandler( NULLMSGTYPE, NULLMSGSUBTYPE, (HandlerPtr)NULL,
  1323.     (HandlerPtr *)NULL );
  1324.  
  1325.   /* Initialize this logical nodes network port and */
  1326.   /* Ethernet interface for network environment.     */
  1327.  
  1328.     {
  1329.  
  1330.       MMNetPort = 1;  /* Hack to let it be > 0, Eric Jul, April 1986 */
  1331.       status = MMSS_Success;
  1332.       if ( mSUCCESS(status) )
  1333.     {
  1334.         status = InitEthernet(fPort);
  1335.         MXTraceMsg(5, "After InitEthernet status = %08x\n", status);
  1336.         if ( mSUCCESS(status) )
  1337.           { 
  1338.         /* Make upcall to locate the LNN in the HOTS table */
  1339.         if ( mSUCCESS(MMUpcallHandler[HOTSSEARCHPTR]( MMLocalLNN,  
  1340.                                   &info )) )
  1341.           { 
  1342.             info->NodeNetPort = MMNetPort;
  1343.             mEtherCopy( &(MMLocalEtherNet), &(info->EtherAddr) );
  1344.           }
  1345.           }
  1346.         else return(status);
  1347.     }
  1348.     }
  1349.  
  1350.     THead.TPrev = THead.TNext = &THead;
  1351.     TimerActive = FALSE;
  1352.     MMBuildMsg(&SNpacket.EnetData, NULLMSGTYPE, NULLMSGID, 0, 0);
  1353.     
  1354.     KMDSetSnap(EtherStats);         /* Define snapshot procedure to KMD */
  1355.     KMDSetSnap(MMStats);
  1356.  
  1357.     /* For more information, see notes where the vMM* variables are defined */
  1358.     assert(vMMTickSize > 0);
  1359.     assert(vMMSendWindow > 0);
  1360.     assert(2*vMMSendWindow + 1 < SEQRANGE);
  1361.     assert(vMMACKTimeout < vMMMsgTimeout);
  1362.  
  1363.     /* Now a few silly outputs to satisfy a messedup kernel programmer.
  1364.        Remove at any time. */
  1365.     MXTraceMsg(8, "HOTS Record Size = %d\n", sizeof(HOTSRecord));
  1366.     MXTraceMsg(8, "EnetPacket size  = %d\n", sizeof(EnetPacket));
  1367.     MXTraceMsg(8, "MsgHdr size      = %d\n", sizeof(MessageHeader));
  1368.     assert(sizeof(MessageHeader) == 48);
  1369.   return status;
  1370. }
  1371.  
  1372.  
  1373. /***********************************************************************/
  1374. /*                                                                     */
  1375. /*                    MMInitHOTSEntry, MMInitHOTSLNN                   */
  1376. /*                                                                     */
  1377. /*  Procedures to be called to initialize the HOTS table entry for a   */
  1378. /*  logical node.  MMInitHOTSLNN initializes the entry given the LNN   */
  1379. /*  while MMInitHOTSEntry takes the pointer to the HOTS entry          */
  1380. /***********************************************************************/
  1381.  
  1382. void MMInitHOTSEntry(fHOTS)
  1383. register HOTSRecord     *fHOTS;
  1384. {
  1385.     MXTraceMsg(5, "MMInitHOTSEntry  for LNN %d\n", fHOTS->LNN);
  1386.     fHOTS->ToSendPtr            =   NULLFP;
  1387.     fHOTS->SentPtr              =   NULLFP;
  1388.     MMInitList(fHOTS->RecvPtr);
  1389.     fHOTS->AckExpected          =   0;
  1390.     fHOTS->NextMsgToSend        =   0;
  1391.     fHOTS->NextSeqNo            =   0;
  1392.     fHOTS->TooFar               =   vMMSendWindow;
  1393.     fHOTS->MsgExpected          =   0;
  1394.     fHOTS->LatestAck            =   PrvSeq(fHOTS->MsgExpected);
  1395.     fHOTS->SendWindowSize       =   0;
  1396.     fHOTS->OutOfOrderCount      =   0;
  1397.     fHOTS->Timed                =   FALSE;
  1398.     fHOTS->AckTimerCount        =   0;
  1399.     fHOTS->MsgTimerCount        =   0;
  1400.     fHOTS->TNext                =   fHOTS;
  1401.     fHOTS->TPrev                =   fHOTS;
  1402.     fHOTS->NakSent              =   FALSE;
  1403.     fHOTS->FirstFCMsgSent       =   FALSE;
  1404.     fHOTS->RetransCount         =   0;
  1405.     fHOTS->NAKsSent = fHOTS->NAKsRecv = fHOTS->MsgDropped   =   0;
  1406.     fHOTS->ACKsSent = fHOTS->ACKsRecv                       =   0;
  1407.     fHOTS->MsgDelivered = fHOTS->MsgAccepted                =   0;
  1408. }
  1409.  
  1410. KKStatus MMInitHOTSLNN(fLNN)
  1411. NodeNum             fLNN;
  1412. {
  1413.     HOTSRecord     *HOTSPtr;
  1414.     KKStatus        status;
  1415.  
  1416.     MXTraceMsg(4, "MMInitHOTSLNN for LNN %d\n", fLNN);
  1417.  
  1418.     /* Call higher level routine to search HOTS table */
  1419.     status = MMUpcallHandler[HOTSSEARCHPTR](fLNN, &HOTSPtr);  
  1420.  
  1421.     if ( ! mSUCCESS(status) ) return status;
  1422.     
  1423.     MMInitHOTSEntry(HOTSPtr);
  1424.     return MMSS_Success;
  1425. }
  1426.  
  1427. void MMRemoteNodeDeath(fHOTS)
  1428. register HOTSRecord *fHOTS;
  1429. /* This routine will cleanup all field that concern the
  1430.    sliding window protocol.
  1431.    This includes dropping the entry from timeout queues,
  1432.    discarding and deallocating pending messages, and
  1433.    resetting all fields to an initial value.
  1434.    NB: This routine updates the timer queues and calls
  1435.    free.
  1436. */
  1437. {
  1438.     register FramePtr       FP;
  1439.  
  1440.     /* Called to clean up when a node dies. */
  1441.     DebugMsg(4,     "MMRemoteNodeDeath: LNN = %d\n", fHOTS->LNN);
  1442.     MXTraceMsg(2,   "MMRemoteNodeDeath: LNN = %d\n", fHOTS->LNN);
  1443.  
  1444.     if (fHOTS->Timed) {
  1445.     MXTraceMsg(4, "Removing from timing queue.\n");
  1446.     fHOTS->TNext->TPrev     =   fHOTS->TPrev;
  1447.     fHOTS->TPrev->TNext     =   fHOTS->TNext;
  1448.     fHOTS->Timed            =   FALSE;
  1449.     };
  1450.  
  1451.     /* Drop old messages from queues. */
  1452.     while (fHOTS->SentPtr != NULL) {
  1453.     QueueRmv(fHOTS->SentPtr, FP, Next);
  1454.     MXTraceMsg(2, "Discarding unacked msg seq. %d\n",
  1455.       FP->packet.EnetData.MsgHdr.MsgSeq);
  1456.     MXTraceMsg(2, "MsgId 0%06x, MsgType 0x%02x, Subtype 0x%02x\n",
  1457.       FP->packet.EnetData.MsgHdr.MsgId,
  1458.       FP->packet.EnetData.MsgHdr.MsgType,
  1459.       FP->packet.EnetData.MsgHdr.MsgSubtype);
  1460.     free((char *) FP);
  1461.     };
  1462.  
  1463.     while (fHOTS->ToSendPtr != NULL) {
  1464.     QueueRmv(fHOTS->ToSendPtr, FP, Next);
  1465.     MXTraceMsg(2, "Discarding unsent msg seq. %d\n",
  1466.       FP->packet.EnetData.MsgHdr.MsgSeq);
  1467.     MXTraceMsg(2, "MsgId 0%06x, MsgType 0x%02x, Subtype 0x%02x\n",
  1468.       FP->packet.EnetData.MsgHdr.MsgId,
  1469.       FP->packet.EnetData.MsgHdr.MsgType,
  1470.       FP->packet.EnetData.MsgHdr.MsgSubtype);
  1471.     free((char *) FP);
  1472.     };
  1473.  
  1474.     MXTraceMsg(3, "End MMRemoteNodeDeath\n");
  1475.  
  1476.     /* Reinitialize the sliding window protocol fields. */
  1477.     MMInitHOTSEntry(fHOTS);
  1478. }
  1479.  
  1480. /************************************************************/
  1481. /*                                                          */
  1482. /*                    MMAllocateMsg                         */
  1483. /*                                                          */
  1484. /*  MMAllocateMsg allocates a contiguous message buffer of  */
  1485. /*  fSize bytes (plus a header).                            */
  1486. /*  Buffer management is done by Guy Almes  version of      */
  1487. /*  malloc tuned to be optimal for message sizes.           */
  1488. /*  If message sizes grow beyond 2044, malloc should be     */
  1489. /*  retuned.                                                */
  1490. /*                                                          */
  1491. /*  Possible status codes:                                  */
  1492. /*      MMSS_Success, MMSK_NoMem, MMSF_MsgOvfl              */
  1493. /*                                                          */
  1494. /************************************************************/
  1495.  
  1496. KKStatus  MMAllocateMsg( fSize,    /* Data Size (in bytes)  */
  1497.        /* returns */ fMsg      /* Message Buffer        */
  1498.             )
  1499.   int           fSize;
  1500.   MessagePtr   *fMsg;
  1501. {
  1502.   register  MessagePtr       newmsg;
  1503.   register  MessageHeaderPtr hdr;
  1504.  
  1505.   MXTraceMsg(5, "MMAllocateMsg( %d )\n", fSize);
  1506.  
  1507.   if ( ((unsigned int) fSize) > MAXMESSAGESIZE )
  1508.     return MMSF_MsgOvfl;
  1509.  
  1510.   newmsg = (MessagePtr) malloc( (unsigned) (fSize+MessageHdrSize) );
  1511.  
  1512.   if ( newmsg == NULL )
  1513.     return MMSK_NoMem;
  1514.   hdr = &newmsg->MsgHdr;
  1515.   hdr->MsgVersion = VER_MsgModule;
  1516.   hdr->MsgSize = fSize;
  1517.   hdr->MsgSrc = MMLocalLNN;
  1518.   hdr->SrcSinPort = MMLocalEtherNet.sin_port;
  1519.   hdr->SrcSinAddr = MMLocalEtherNet.sin_addr;
  1520.   hdr->SrcIncarnationId = nodeIncarnationId;
  1521.  
  1522.   *fMsg = newmsg;
  1523.  
  1524.   cMMMsgAllocCount++;
  1525.  
  1526.   MXTraceMsg(6, "new msg address %d\n", newmsg);
  1527.  
  1528.   return MMSS_Success;
  1529. }
  1530.  
  1531. /************************************************************/
  1532. /*                                                          */
  1533. /*                    MMDeallocateMsg                       */
  1534. /*                                                          */
  1535. /*   MMDeallocateMsg releases the buffer storage associated */
  1536. /*  with the specified message.  See MMAllocateMsg.
  1537. /*                                                          */
  1538. /************************************************************/
  1539.  
  1540. void  MMDeallocateMsg( fMsg     /* Message Buffer */
  1541.              )
  1542.   MessagePtr fMsg;
  1543. {
  1544.   MXTraceMsg(5, "MMDeallocateMsg(0x%06x)\n", fMsg);
  1545.  
  1546.   if ( fMsg != NULL ) {
  1547.       free( (char *) fMsg );
  1548.       cMMMsgDeAllocCount++;
  1549.   }
  1550.   MXTraceMsg(6, "MMDeallocateMsg returns\n");
  1551. }
  1552.  
  1553. /************************************************************/
  1554. /*                                                          */
  1555. /*                   MMBuildMsg                             */
  1556. /*                                                          */
  1557. /*   MMBuildMsg initializes the header of the specified     */
  1558. /*  message buffer with the user-defined attributes.  The   */
  1559. /*  message source logical node number is automatically set */
  1560. /*  to the users logical node number.  The message number   */
  1561. /*  is not assigned until  MMSendMsg is called.             */
  1562. /*                                                          */
  1563. /*  Possible status codes:                                  */
  1564. /*      MMSS_Success, MMSF_MsgOvfl                          */
  1565. /*                                                          */
  1566. /************************************************************/
  1567.  
  1568. void MMBuildMsg( fMsg,         /* Message Buffer    */
  1569.               fType,        /* Message Type      */
  1570.               fSubtype,     /* Message Subtype   */
  1571.               fDestination, /* Destination LNN   */
  1572.               fSize         /* Message Data Size */
  1573.             )               /*  (in bytes)       */
  1574.   register  MessagePtr     fMsg;
  1575.         MessageType    fType;
  1576.         MessageSubtype fSubtype;
  1577.         NodeNum        fDestination;
  1578.         unsigned int   fSize;
  1579. {
  1580.   register MessageHeaderPtr hdr;
  1581.  
  1582.   MXTraceMsg(5, "MMBuildMsg( %d, 0x%08x, 0x%08x, %d, %d )\n", fMsg, fType,
  1583.             fSubtype, fDestination, fSize);
  1584.  
  1585.   hdr = &fMsg->MsgHdr;
  1586.   hdr->MsgVersion = VER_MsgModule;
  1587.   hdr->MsgSrcPort = NULLEDENPORT;
  1588.   hdr->MsgSrc = MMLocalLNN;
  1589.   hdr->MsgDestPort = NULLEDENPORT;
  1590.   hdr->MsgDest = fDestination;
  1591.   hdr->MsgType = fType;
  1592.   hdr->MsgSubtype = fSubtype;
  1593.   hdr->MsgSize = fSize;
  1594.   hdr->SrcSinPort = MMLocalEtherNet.sin_port;
  1595.   hdr->SrcSinAddr = MMLocalEtherNet.sin_addr;
  1596.   hdr->SrcIncarnationId = nodeIncarnationId;
  1597.  
  1598.   return;
  1599. }
  1600.  
  1601. /************************************************************/
  1602. /*                                                          */
  1603. /*                       MMSendMsg                          */
  1604. /*                                                          */
  1605. /*  Send out a message.                                     */
  1606. /*                                                          */
  1607. /*  Possible status codes:                                  */
  1608. /*     MMSS_Success, MMSK_NoMem, MMSF_MsgOvfl, MMSF_BadNode,*/
  1609. /*     MMSF_NodeDown                                        */
  1610. /*                                                          */
  1611. /************************************************************/
  1612.  
  1613. KKStatus  MMSendMsg( fMsg )
  1614. MessagePtr fMsg;         /* Message Buffer          */
  1615. {
  1616.   DeviceAddr addr;
  1617.   KKStatus   status;
  1618.  
  1619.   MXTraceMsg(4, "MMSendMsg(0x%06x) to node %d\n", fMsg, fMsg->MsgHdr.MsgDest);
  1620.  
  1621.   if (fMsg->MsgHdr.MsgSize > MAXMESSAGESIZE)
  1622.     return MMSF_MsgOvfl;
  1623.  
  1624.   if (fMsg->MsgHdr.MsgDest == GetLNN())
  1625.     return MMSF_BadNode;
  1626.   
  1627.   AssignMsgId (&fMsg->MsgHdr.MsgId);
  1628.   fMsg->MsgHdr.BroadcastMask = NULLNODE;
  1629.   fMsg->MsgHdr.SNType = SNNORMAL;
  1630.  
  1631.   cMMMsgSentSynchCount++;
  1632.  
  1633.   status = SendOutMsg(fMsg, &addr);
  1634.   return status;
  1635. }
  1636.  
  1637. KKStatus  MMSendRawMsg( fMsg )
  1638. MessagePtr   fMsg;         /* Message Buffer */
  1639. {
  1640.   DeviceAddr    addr;
  1641.   KKStatus      status;
  1642.  
  1643.   MXTraceMsg(4, "MMSendRawMsg(0x%06x) to node %d\n", fMsg,
  1644.       fMsg->MsgHdr.MsgDest);
  1645.  
  1646.   if (fMsg->MsgHdr.MsgSize > MAXMESSAGESIZE)
  1647.     return MMSF_MsgOvfl;
  1648.   
  1649.   if (fMsg->MsgHdr.MsgDest == GetLNN())
  1650.     return MMSF_BadNode;
  1651.   
  1652.   AssignMsgId (&fMsg->MsgHdr.MsgId);
  1653.   fMsg->MsgHdr.BroadcastMask = NULLNODE;
  1654.   fMsg->MsgHdr.SNType = SNRAWMSG;
  1655.  
  1656.   cMMMsgSentRawCount++;
  1657.  
  1658.   status = SendOutMsg(fMsg, &addr);
  1659.   return status;
  1660. }
  1661.  
  1662. /************************************************************/
  1663. /*                                                          */
  1664. /*                   MMBroadcastMsg                         */
  1665. /*                                                          */
  1666. /*  MMBroadcastMsg is the standard primitive for transmitting*/
  1667. /*  a message to more than one logical node at a time.  It  */
  1668. /*  disassembles the message, assigns a message number, and */
  1669. /*  transmits the message to the target nodes.  The assigned*/
  1670. /*  message number is returned in fMsgId.  fNumNodes        */
  1671. /*  specifies the number of logical nodes the message is to */
  1672. /*  be sent to and must be greater than 0.  In this case,   */
  1673. /*  fNodeList specifies the logical nodes the message is to */
  1674. /*  be sent to.  If fNumNodes is equal to BROADCAST, the    */
  1675. /*  message is broadcast to all nodes in the network and the*/
  1676. /*  contents of fNodeList is ignored.  If fNumNodes is equal*/
  1677. /*  to MULTICAST, the message is broadcast to all nodes     */
  1678. /*  accepting the multicast address contained in fNodeList: */
  1679. /*                                                          */
  1680. /*      <--- high                         low --->          */
  1681. /*      fNodeList[2] | fNodeList[1] | fNodeList[0]          */
  1682. /*                                                          */
  1683. /*  Broadcast messages are restricted to MAXMESSAGESIZE bytes*/
  1684. /*  and reception by any or all of the target nodes is not  */
  1685. /*  guaranteed.   MMBroadcastMsg operates synchronously.    */
  1686. /*  Control is not returned to the caller until the message */
  1687. /*  has been successfully transmitted to all target nodes or*/
  1688. /*  an error is detected.                                   */
  1689. /*                                                          */
  1690. /*  Possible status codes:                                  */
  1691. /*      MMSS_Success, MMSF_MsgOvfl, MMSF_NodeDown, MMSF_IPCx,*/
  1692. /*      MMSF_Enetx                                           */
  1693. /*                                                          */
  1694. /************************************************************/
  1695.  
  1696. KKStatus  MMBroadcastMsg   ( fMsg )
  1697. MessagePtr  fMsg;      /* Message Buffer*/
  1698. {
  1699.   DeviceAddr     dest;
  1700.  
  1701.   MXTraceMsg(3,"MMBroadcastMsg( 0x%08x) MsgType 0x02x, SubType 0x%02x\n",
  1702.     fMsg, fMsg->MsgHdr.MsgType, fMsg->MsgHdr.MsgSubtype);
  1703.  
  1704. /*  The following test should test against the max broadcast size
  1705.     which for UNIX 4.2bsd is smaller than MAXMESSAGESIZE */
  1706.  
  1707.   if (fMsg->MsgHdr.MsgSize > MAXMESSAGESIZE)
  1708.     return MMSF_MsgOvfl;
  1709.  
  1710.   AssignMsgId (&fMsg->MsgHdr.MsgId);
  1711.  
  1712.   {
  1713.         dest.DeviceLocal = False;
  1714.         dest.DeviceEnet = MMBroadcastAddr;
  1715.         MXTraceMsg(5,
  1716.         "MMBroadcastMsg: EthAddr in dest.DeviceEnet = %s\n",
  1717.         inet_ntoa(dest.DeviceEnet.sin_addr));
  1718.         MXTraceMsg(5, "MMBroadcastMsg: dest.DeviceEnet.sin_port = %d\n",
  1719.                ntohs(dest.DeviceEnet.sin_port));
  1720.         MXTraceMsg(5, "MMBroadcastMsg: dest.DeviceEnet.sin_family = %d\n",
  1721.                dest.DeviceEnet.sin_family);
  1722.         fMsg->MsgHdr.SNType = SNBROADCAST;
  1723.         cMMBroadcastHOSTCount++;
  1724.         return (SendOutMsg(fMsg, &dest));
  1725.   }
  1726. }
  1727.  
  1728. /****************************************************************/
  1729. /*                                                              */
  1730. /*                     MMEthernetInterrupt                      */
  1731. /*                                                              */
  1732. /****************************************************************/
  1733. #ifdef xkernel
  1734. int MMEthernetInterrupt()
  1735. {
  1736.   /* we should never get here */
  1737.   MXTraceMsg(1, "Should never get here in msgCode.c!\n");
  1738.   assert(FALSE);
  1739. }
  1740. #else
  1741. int MMEthernetInterrupt()
  1742. {
  1743.        int           nbytes;
  1744.        MessagePtr    newmsg;
  1745.        EnetPacket    packet;
  1746.   register EnetPacketPtr enet;
  1747.        KKStatus      status;
  1748.        struct sockaddr senderAddr;
  1749.        int senderAddrSize;
  1750.        int count;
  1751.  
  1752.     count = 0;
  1753.     cMMEthernetIntCount++;
  1754.     do {
  1755.     MXTraceMsg(4, "**** MMEthernetInterrupt: pass %d.\n",++count);
  1756.  
  1757.     enet = &packet;
  1758.     nbytes = recvfrom( MMEtherFile, (char *) enet, sizeof(EnetPacket), 0,
  1759.                &senderAddr, &senderAddrSize);
  1760.  
  1761.     if ( nbytes < 0 ) {
  1762.         status = mSystemError( errno );
  1763.         if ( status == SYSK_EWOULDBLOCK ) {
  1764.         MXTraceMsg(5, "EWOULDBLOCK so no more reading to do.\n");
  1765.         status = MMSS_Success;
  1766.         break;
  1767.         }
  1768.         if ( status == SYSK_EINTR ) continue;
  1769.         MXTraceMsg(1,"recvfrom error: %08x.\n",status);
  1770.         break;
  1771.     }
  1772.  
  1773.     status = MMSS_Success;
  1774.     if ( MMTrace ) {
  1775.         MXTraceMsg(5, "%d requested, %d bytes read.\n", 
  1776.         sizeof(EnetPacket), nbytes);
  1777.         MXTraceMsg(4,
  1778.         "EtherInt> MsgId 0x%06x Seq %d SNType %d SrcLNN %d\n",
  1779.         packet.EnetData.MsgHdr.MsgId, packet.EnetData.MsgHdr.MsgSeq,
  1780.         packet.EnetData.MsgHdr.SNType, packet.EnetData.MsgHdr.MsgSrc);
  1781.         MXTraceMsg(4, "MsgType 0x%06x,  MsgSubtype 0x%06x\n",
  1782.         packet.EnetData.MsgHdr.MsgType,
  1783.         packet.EnetData.MsgHdr.MsgSubtype);
  1784.     };
  1785.  
  1786. #ifdef DROPTEST
  1787.     /* DROPTEST:
  1788.      *      For debugging: Asks the debugger if the message should be
  1789.      *      dropped.  Input is read and if a "r" is met
  1790.      *      then the message is retained else if a "d" is met then
  1791.      *      the message is dropped.  The rest of the line is thrown away.
  1792.      *      The idea of this test is due to the late Bob Bandes.
  1793.      */
  1794.     {
  1795.     char ch, dumpch;
  1796.     printf(
  1797.         "EtherInt> MsgId 0x%06x Seq %d SNType %d SrcLNN %d\n",
  1798.         packet.EnetData.MsgHdr.MsgId, packet.EnetData.MsgHdr.MsgSeq,
  1799.         packet.EnetData.MsgHdr.SNType, packet.EnetData.MsgHdr.MsgSrc);
  1800.     printf("MsgType 0x%06x,  MsgSubtype 0x%06x\n",
  1801.         packet.EnetData.MsgHdr.MsgType,
  1802.         packet.EnetData.MsgHdr.MsgSubtype);
  1803.     printf("$$$$ DROP TEST (type 'd' to drop, 'r' to retain) >");
  1804.     (void) fflush(stdout);
  1805.     do {
  1806.         ch = getchar();
  1807.     } while (ch != 'r' && ch != 'd');
  1808.     do {dumpch = getchar();} while (dumpch != '\n');
  1809.     if (ch == 'd') {
  1810.         printf("  Message DROPPED.\n");
  1811.         return;
  1812.     }
  1813.     printf("   Message Retained.\n");
  1814.     };
  1815. #endif DROPTEST
  1816.  
  1817.     /*
  1818.      * Ignore our own broadcasts.  This is tricky work since
  1819.      * we want to be able to detect a duplicate node being booted,
  1820.      * and the initial boot messages is sent out as a broadcast.
  1821.      * The only thing done with that message, is to send a reply
  1822.      * saying "possession is 9/10ths of the law" so the duplicate
  1823.      * will trash itself.
  1824.      */
  1825.       if ( /* This test takes care of the usual case */
  1826.      ( enet->EnetData.MsgHdr.MsgSrc != MMLocalLNN ) ||
  1827.      /* This test screens out msg from our own incarnation */
  1828.      ( enet->EnetData.MsgHdr.SrcIncarnationId != nodeIncarnationId)
  1829.     ) {
  1830.     if ( enet->EnetData.MsgHdr.MsgVersion == VER_MsgModule ) {
  1831.         status = MMAllocateMsg( MAXMESSAGESIZE, &newmsg);
  1832.         /* BUG: somehow it happens that the following bcopy causes
  1833.            a segmentation fault, so therefore MAXMESSAGESIZE 
  1834.            as to ensure enough space (brute force), Eric Jul, 1984-06-03,
  1835.            should be : enet->EnetData.MsgHdr.MsgSize */
  1836.         if ( mSUCCESS(status) ) {
  1837.         newmsg->MsgHdr = enet->EnetData.MsgHdr;
  1838.         bcopy ((char *)enet->EnetData.MsgData,(char *)newmsg->MsgData, 
  1839.             (int) enet->EnetData.MsgHdr.MsgSize);
  1840.  
  1841.         HoldSigs(); /* Protect QueueTask against signals. */
  1842.         QueueTask( (HandlerPtr)MMReceiveEtherHandler, newmsg);
  1843.         ReleaseSigs();
  1844.         }
  1845.           else ErrMsg(">> MMEthernetInterrupt got no buffer 0x%02x\n",
  1846.             status);
  1847.       }
  1848.       else
  1849.        MXTraceMsg(1, "MMEthernetInterrupt: Incompatible version #.\n");
  1850.      } else MXTraceMsg(4, "Dropping own msg (broadcast)\n");
  1851.     } while( 1 );
  1852.  
  1853.     if ( ! mSUCCESS(status) ) {
  1854.     DebugMsg(1,"MMEthernetInterrupt Error: 0x%06x.\n",status );
  1855.     }
  1856.     MXTraceMsg(5, "***** End of MMEthernetInterrupt\n");
  1857. }
  1858. #endif
  1859.  
  1860.  
  1861. /****************************************************************/
  1862. /*                                                              */
  1863. /*                          MMReceiveEtherHandler               */
  1864. /*                                                              */
  1865. /*  MMReceiveEtherHandler handles an incoming message (from the */
  1866. /*  Ether), takes care of flow control & piggybacked ACKs.      */
  1867. /*  If the message is not out of order, it and any other in-    */
  1868. /*  order messages are passed to the appropriate handlers by    */
  1869. /*  dispatching the handlers.                                   */
  1870. /*                                                              */
  1871. /****************************************************************/
  1872.  
  1873. static HResult MMReceiveEtherHandler(fmsg)
  1874. MessagePtr fmsg;
  1875. {
  1876.   KKStatus   status;
  1877.   int        MsgLNN;
  1878.   MessagePtr MP;
  1879.   MsgSeqType Villain, PiggyBackAck;
  1880.   int        sendWindowBlockedAtEntry;
  1881.  
  1882.   register MessageHeaderPtr hdr;
  1883.   
  1884.   if (fmsg == NULL) return;
  1885.  
  1886.   hdr = &fmsg->MsgHdr;
  1887.   MsgLNN = hdr->MsgSrc;
  1888.  
  1889.   if ( MMTrace ) {
  1890.     MXTraceMsg(3,
  1891.            "MMReceiveEtherHandler, MsgId 0x%02x, MsgSeq %d, SNType %d\n",
  1892.            hdr->MsgId, hdr->MsgSeq, hdr->SNType);
  1893.     MXTraceMsg(3, "SrcLNN %d, MsgType 0x%06x, MsgSubtype 0x%06x\n",
  1894.            hdr->MsgSrc, hdr->MsgType, hdr->MsgSubtype);
  1895.     MXTraceMsg(5, "SrcSinPort %d, sin_addr: %s, IncarnationId: %.15s\n",
  1896.            ntohs(hdr->SrcSinPort), inet_ntoa(*(struct in_addr *)&hdr->SrcSinAddr),
  1897.            4+ctime(&hdr->SrcIncarnationId));
  1898.   }
  1899.  
  1900.   /* Make Upcall to find HOTS entry for MsgLNN; this might insert
  1901.      or update the HOTS based on the hostIncarnationId */
  1902.   status = MMUpcallHandler[CHECKMSG]( fmsg, &HOTS);
  1903.   if (!mSUCCESS(status)) {
  1904.     /* Use the NOHOTSEntry Upcall to handle the situation and retry */
  1905.     MXTraceMsg(1, "CHECKMSG failed LNN %d, status = 0x%08x\n",
  1906.            MsgLNN, status);
  1907.     if (!mSUCCESS(status)) {
  1908.       MXTraceMsg(1,
  1909.          "MMReceiveEtherHandler: Unknown LNN = %d; status = 0x%08x\n",
  1910.          fmsg->MsgHdr.MsgSrc, status);
  1911.       MXTraceMsg(1, "SrcPort %d, SinAddr %s, Incarnation %.15s\n",
  1912.          ntohs(hdr->SrcSinPort),
  1913.          inet_ntoa(*(struct in_addr *)&hdr->SrcSinAddr),
  1914.          4+ctime(&hdr->SrcIncarnationId));
  1915.       MXTraceMsg(1, "<<< Message Dropped >>>\n");
  1916.       MMDeallocateMsg(fmsg);
  1917.       return;
  1918.     }
  1919.   }
  1920.  
  1921.   if ( (hdr->SNType == SNBROADCAST) ) {
  1922.     /* Dispatch it right away. */
  1923.     status = MMDispatchMsg( fmsg );
  1924.     if ( ! mSUCCESS(status) ) {
  1925.       if(!mSUCCESS(GetEdenMsg( (int) status, TextSize, ErrorText, 0 ))){
  1926.     (void) sprintf(ErrorText, "Status 0x%06x", status);
  1927.       }
  1928.       ErrMsg("Unable to dispatch incoming message:\n%s\n",
  1929.          ErrorText );
  1930.       MMDeallocateMsg(fmsg);
  1931.     }
  1932.     return;
  1933.   };
  1934.  
  1935.   if (HOTS->NodeStat == Dead) {
  1936.     /* This should not happen since CheckMsg should fix it */
  1937.     /* Not found in HOTS, so if it is not a RAW msg then call Upcall 
  1938.        handler to deal with missing HOTS entry. */
  1939.     if (hdr->SNType == SNRAWMSG) { /* Then just dispatch it.*/
  1940.       status = MMDispatchMsg( fmsg );
  1941.     }
  1942.     if ( ! mSUCCESS(status) ) {
  1943.       if(!mSUCCESS(GetEdenMsg( (int) status, TextSize, ErrorText,
  1944.                   0 ))) {
  1945.     (void) sprintf(ErrorText, "Status 0x%06x", status);
  1946.       }
  1947.       ErrMsg("Unable to dispatch incoming message:\n%s\n",
  1948.          ErrorText );
  1949.       MMDeallocateMsg(fmsg);
  1950.     }
  1951.     return;
  1952.   }
  1953.  
  1954.   sendWindowBlockedAtEntry = (HOTS->SendWindowSize >= vMMSendWindow);
  1955.     
  1956.   PiggyBackAck = hdr->MsgAck;
  1957.  
  1958.   MXTraceMsg(5, "MsgExp=%d, Seq=%d, TooFar=%d\n",
  1959.          HOTS->MsgExpected, hdr->MsgSeq, HOTS->TooFar);
  1960.  
  1961.   switch (hdr->SNType) {
  1962.  
  1963.   case SNFIRSTFCMSG:  /* First flow-ctrld msg received from this LNN */
  1964.     MXTraceMsg(2, "First msg from %d of %.15s arrived\n",
  1965.            hdr->MsgSrc, 4+ctime(&hdr->SrcIncarnationId));
  1966.     cMMFirstFCMsgCount++;
  1967.     MMUpcallHandler[FIRSTFCMSGRECEIVED](HOTS, fmsg);
  1968.     /* Note: now that the upper layer protocol has been informed that
  1969.        we have received the first flow-controlled msg from this LNN,
  1970.        continue processing the message like any other SNNORMAL msg: */
  1971.  
  1972.   case SNNORMAL:
  1973.     if (hdr->MsgSeq != HOTS->MsgExpected) {
  1974.       /* Out of order message. */
  1975.       MXTraceMsg(2, "Msg #%d out of order MsgExp=%d TooFar=%d\n",
  1976.          hdr->MsgSeq, HOTS->MsgExpected, HOTS->TooFar);
  1977.       if (! HOTS->NakSent ) {
  1978.     HOTS->NakSent = TRUE;
  1979.     HOTS->NAKsSent++;  cMMNAKsSentCount++;
  1980.     MXTraceMsg(2, "Sending NAK of msg #%d to LNN %d\n",
  1981.            HOTS->MsgExpected, HOTS->LNN);
  1982.     SendSubNetPacket(SNNAK, (MessagePtr) NULL);
  1983.       }
  1984.       if (between(HOTS->MsgExpected, hdr->MsgSeq, HOTS->TooFar) &&
  1985.       /* Retain if not duplicate. */
  1986.       (MMEnterInList(HOTS->RecvPtr, hdr->MsgSeq, (integer) fmsg,
  1987.              (integer) NULL)
  1988.        == MMSS_Success)
  1989.       ) {
  1990.     MXTraceMsg(2, "Msg queued.\n");
  1991.     HOTS->OutOfOrderCount++; cMMOutOfOrderCount ++;
  1992.       } else { /* Msg Dropped */
  1993.     MXTraceMsg(2,
  1994.            "Dropping Msg #%d from LNN %d: Dupl. or irrelevant.\n",
  1995.            hdr->MsgSeq, HOTS->LNN);
  1996.     HOTS->MsgDropped++;  cMMMsgDroppedCount++;
  1997.     MMDeallocateMsg(fmsg);
  1998.       }
  1999.       /* Start ACK timer if necessary. */
  2000.       if (!HOTS->AckTimerCount) {
  2001.     /* (use float to prevent integer overflow) */
  2002.     MXTraceMsg(4, "ACK Timer started: %f microseconds.\n",
  2003.            vMMTickSize * (float) vMMACKTimeout); 
  2004.     HOTS->AckTimerCount = vMMACKTimeout;
  2005.     CheckTimer;
  2006.       }
  2007.     } else {
  2008.       register int UnAcked;
  2009.       /* Msg was the expected one. */
  2010.       MXTraceMsg(4, "Msg was expected, seqno  %d\n",
  2011.          HOTS->MsgExpected);
  2012.       HOTS->NakSent = FALSE;
  2013.       MP = fmsg;
  2014.       do {
  2015.     MXTraceMsg(3, "Msg #%d ACCEPTED, LatestAck %d\n",
  2016.            MP->MsgHdr.MsgSeq, HOTS->LatestAck);
  2017.     IncSeq(HOTS->MsgExpected);
  2018.     IncSeq(HOTS->TooFar);
  2019.     HOTS->MsgAccepted++;  cMMMsgAcceptedCount++;
  2020.     MXTraceMsg(4, "MsgExp=%d, Seq=%d, TooFar=%d\n",
  2021.            HOTS->MsgExpected, hdr->MsgSeq, HOTS->TooFar);
  2022.  
  2023.     /* Check ACK: If senders Send Window is near full
  2024.        then force an ACK.  Else start the ACK timer.
  2025.        NOTE: UnAcked = # of unACKed msgs PLUS one. */
  2026.  
  2027.     if ((UnAcked = (int) HOTS->MsgExpected - (int) HOTS->LatestAck) < 0)
  2028.       UnAcked = UnAcked + SEQRANGE;  /* Wraparound. */
  2029.     MXTraceMsg(4, "UnAcked = %d, ForceAck = %d\n",
  2030.            UnAcked, vMMForceAck);
  2031.     if (UnAcked > vMMForceAck) {
  2032.       /* The senders Send Window is filling: Force an
  2033.          ACK to allow sender to free buffers and move window. */
  2034.       MXTraceMsg(3, "Forcing ACK to LNN %d, LatestAck = %d\n",
  2035.              HOTS->LNN, HOTS->LatestAck);
  2036.       HOTS->ACKsSent++;  cMMACKsSentCount++;
  2037.       SendSubNetPacket(SNACK, (MessagePtr) NULL);
  2038.     } else { /* Start the ACK timer. */
  2039.       if (!HOTS->AckTimerCount) {
  2040.         MXTraceMsg(4, "ACK Timer started LNN %d: %d sec.\n",
  2041.                HOTS->LNN, vMMTickSize * vMMACKTimeout);
  2042.         HOTS->AckTimerCount = vMMACKTimeout;
  2043.         CheckTimer;
  2044.       }
  2045.     }
  2046.  
  2047.     status = MMDispatchMsg( MP );
  2048.  
  2049.     if ( ! mSUCCESS(status) ) {
  2050.       if(!mSUCCESS(GetEdenMsg( (int) status, TextSize,
  2051.                   ErrorText, 0 ))) {
  2052.         (void) sprintf(ErrorText, "Status 0x%06x", status);
  2053.       }
  2054.       ErrMsg("Unable to dispatch incoming message:\n%s",
  2055.          ErrorText );
  2056.       ErrMsg("Msg Id = 0x%06x\n", MP->MsgHdr.MsgId);
  2057.       MMDeallocateMsg(MP);
  2058.     }
  2059.     /* Check for dispatchable messages. */
  2060.       } while ((HOTS->OutOfOrderCount) &&
  2061.            mSUCCESS(MMGetFromList(HOTS->RecvPtr, HOTS->MsgExpected, 
  2062.                       (int *)&MP, (int *)NULL)));
  2063.     }
  2064.     endcase /* SNNORMAL */ ;
  2065.  
  2066.   case SNRAWMSG:
  2067.     /* A raw, non-flow controlled message has arrived, dispatch it. */
  2068.     MXTraceMsg(3, "Raw, non-flow controlled msg.\n");
  2069.     status = MMDispatchMsg( fmsg );
  2070.     if ( ! mSUCCESS(status) ) {
  2071.       if(!mSUCCESS(GetEdenMsg( (int) status, TextSize, ErrorText, 0 ))) {
  2072.     (void) sprintf(ErrorText, "Status 0x%06x", status);
  2073.       }
  2074.       ErrMsg("Unable to dispatch incoming message:\n%s\n", ErrorText);
  2075.       MMDeallocateMsg(fmsg);
  2076.     }
  2077.     return;         /* No piggy-back ACK */
  2078.     /* endcase SNRAWMSG */ ;
  2079.  
  2080.   case SNNAK:
  2081.     HOTS->NAKsRecv++;  cMMNAKsRecvCount++;
  2082.     Villain = NxtSeq(hdr->MsgAck);
  2083.     MXTraceMsg(2, "NAK from LNN %d of msg #%d\n", HOTS->LNN, Villain);
  2084.     MXTraceMsg(3, "AckExp=%d, Villain=%d, NextToSend=%d\n",
  2085.            HOTS->AckExpected, Villain, HOTS->NextMsgToSend);
  2086.     if ( between(HOTS->AckExpected, Villain, HOTS->NextMsgToSend) ) {
  2087.       register FramePtr FP, FirstFP;
  2088.       /* Retransmit old frame. */
  2089.       FirstFP=FP=HOTS->SentPtr;
  2090.       do {
  2091.     MXTraceMsg(5, "Queue Search, FP= %d (x%06x), Seq=%d\n",
  2092.            FP, FP, FP->packet.EnetData.MsgHdr.MsgSeq);
  2093.     if (FP->packet.EnetData.MsgHdr.MsgSeq == Villain) {
  2094.       MXTraceMsg(2, "NAK causing Retransmit of MsgSeq %d\n",
  2095.              FP->packet.EnetData.MsgHdr.MsgSeq);
  2096.       (void) SendFrame(FP);
  2097.       HOTS->RetransCount++; cMMRetransCount++;
  2098.       FP->RetransCount++;
  2099.       break;
  2100.     }
  2101.     FP=FP->Next;
  2102.       } while (FP != FirstFP);
  2103.     }
  2104.     MMDeallocateMsg(fmsg);
  2105.  
  2106.     endcase /* SNNAK */;
  2107.  
  2108.   case SNBROADCAST:
  2109.     /* Should not happen. */
  2110.     MMDeallocateMsg(fmsg);
  2111.     return;
  2112.     /* endcase; */
  2113.  
  2114.   default:
  2115.     /* Assume ACK. (Piggyback ack already stripped off, so no work.) */
  2116.     HOTS->ACKsRecv++;  cMMACKsRecvCount++;
  2117.     MMDeallocateMsg(fmsg);
  2118.     endcase /* Default */;
  2119.       
  2120.   } /* Switch */;
  2121.     
  2122.   /* Now utilize the piggybacked acknowledgement. */
  2123.   MXTraceMsg(4, "AckExp=%d, PiggyBACK=%d, NextToSend=%d\n",
  2124.          HOTS->AckExpected, PiggyBackAck, HOTS->NextMsgToSend);
  2125.   while (between(HOTS->AckExpected, PiggyBackAck, HOTS->NextMsgToSend)) {
  2126.     register FramePtr FP;
  2127.  
  2128.     MXTraceMsg(4, "Piggyback ACK = %d\n", PiggyBackAck);
  2129.  
  2130.     /* Find msg in list (will be first normally) */
  2131.     QueueRmv(HOTS->SentPtr, FP, Next);
  2132.     while (FP->packet.EnetData.MsgHdr.MsgSeq != HOTS->AckExpected) {
  2133.       /* Not it; put at end and try next (note, it has to be there) */
  2134.       QueueIns(HOTS->SentPtr, FP, Next);
  2135.       MXTraceMsg(5, "Queue search FP= %d(x%06x), Seq= %d\n",
  2136.          FP, FP, FP->packet.EnetData.MsgHdr.MsgSeq);
  2137.       QueueRmv(HOTS->SentPtr, FP, Next);
  2138.     }
  2139.  
  2140.     /* Found, now free it and move window pointers. */
  2141.     IncSeq(HOTS->AckExpected);
  2142.     /* Stop Msg Timer if count goes to zero. */
  2143.     HOTS->SendWindowSize--;
  2144.     HOTS->MsgDelivered++;  cMMMsgDeliveredCount++;
  2145.     MXTraceMsg(6, "free (%d=x%06x)\n", FP, FP);
  2146.     free((char *) FP);
  2147.   }
  2148.   /* Stop msg timer if no more msgs are outstanding. */
  2149.   if (!(HOTS->SendWindowSize)) HOTS->MsgTimerCount = 0;
  2150.  
  2151.   /* Send queued messages if there are any and the window is not full. */
  2152.   MXTraceMsg(5, "SWSize %d, NextMsgToSend %d\n",
  2153.          HOTS->SendWindowSize, HOTS->NextMsgToSend);
  2154.   while (HOTS->ToSendPtr != NULL && HOTS->SendWindowSize < vMMSendWindow) {
  2155.     register FramePtr FP;
  2156.     QueueRmv(HOTS->ToSendPtr, FP, Next);
  2157.     MXTraceMsg(4, "Sending blocked msg seq %d\n",
  2158.            FP->packet.EnetData.MsgHdr.MsgSeq);
  2159.     IncSeq(HOTS->NextMsgToSend);
  2160.     HOTS->SendWindowSize++;
  2161.     QueueIns(HOTS->SentPtr, FP, Next);
  2162.     (void) SendFrame(FP);
  2163.   }
  2164.   if (sendWindowBlockedAtEntry && (HOTS->SendWindowSize < vMMSendWindow))
  2165.     MMUpcallHandler[SENDWINDOWNOTFULL](HOTS);
  2166. }
  2167.